diff options
| author | Keith Packard <keithp@keithp.com> | 2017-05-26 00:20:17 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2017-05-26 00:20:17 -0700 | 
| commit | 2e82051a6aaaccf1e8a242f9c8141e4167e652d2 (patch) | |
| tree | c0f9642d04f28850c9d60a07266f36c685452fef | |
| parent | 222158581887b5f9e8b9843d14321c313fa023fa (diff) | |
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 <keithp@keithp.com>
| -rw-r--r-- | altoslib/AltosEepromRecordMega.java | 1 | ||||
| -rw-r--r-- | altoslib/AltosFlightReader.java | 2 | ||||
| -rw-r--r-- | altoslib/AltosFlightSeries.java | 17 | ||||
| -rw-r--r-- | altoslib/AltosFlightStats.java | 111 | ||||
| -rw-r--r-- | altoslib/AltosReplayReader.java | 117 | ||||
| -rw-r--r-- | altoslib/AltosTelemetryFile.java | 1 | ||||
| -rw-r--r-- | altoslib/AltosTimeSeries.java | 56 | ||||
| -rw-r--r-- | altosui/AltosFlightUI.java | 2 | ||||
| -rw-r--r-- | altosui/AltosUI.java | 3 | ||||
| -rw-r--r-- | altosuilib/AltosDisplayThread.java | 26 | 
10 files changed, 218 insertions, 118 deletions
| 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<AltosState>	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<AltosState> 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<AltosTimeValue> {  		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<AltosTimeValue> {  		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<AltosTimeValue> {  		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); | 
