diff options
Diffstat (limited to 'altoslib')
| -rw-r--r-- | altoslib/AltosFlightStats.java | 7 | ||||
| -rw-r--r-- | altoslib/AltosKML.java | 289 | 
2 files changed, 222 insertions, 74 deletions
| diff --git a/altoslib/AltosFlightStats.java b/altoslib/AltosFlightStats.java index ea1a9675..6bb83581 100644 --- a/altoslib/AltosFlightStats.java +++ b/altoslib/AltosFlightStats.java @@ -27,6 +27,8 @@ public class AltosFlightStats {  	public double		max_acceleration;  	public double[]		state_speed = new double[AltosLib.ao_flight_invalid + 1];  	public double[]		state_enter_speed = new double[AltosLib.ao_flight_invalid + 1]; +	public double[]		state_enter_height = new double[AltosLib.ao_flight_invalid + 1]; +	public double[]		state_enter_gps_height = new double[AltosLib.ao_flight_invalid + 1];  	public double[]		state_accel = new double[AltosLib.ao_flight_invalid + 1];  	public double[]		state_time = new double[AltosLib.ao_flight_invalid + 1];  	public String		product; @@ -134,6 +136,11 @@ public class AltosFlightStats {  		if (0 <= state && state <= AltosLib.ao_flight_invalid && delta_time > 0) {  			if (state_enter_speed[state] == AltosLib.MISSING)  				state_enter_speed[state] = series.speed_series.value(start_time); +			if (state_enter_height[state] == AltosLib.MISSING) +				state_enter_height[state] = series.height_series.value(start_time); +			if (state_enter_gps_height[state] == AltosLib.MISSING) +				if (series.gps_height != null) +					state_enter_gps_height[state] = series.gps_height.value(start_time);  			speeds[state].value += series.speed_series.average(start_time, end_time) * delta_time;  			speeds[state].time += delta_time;  			accels[state].value += series.accel_series.average(start_time, end_time) * delta_time; diff --git a/altoslib/AltosKML.java b/altoslib/AltosKML.java index 587b845b..4738ac91 100644 --- a/altoslib/AltosKML.java +++ b/altoslib/AltosKML.java @@ -38,16 +38,18 @@ public class AltosKML implements AltosWriter {  	int			flight_state = -1;  	AltosGPS		prev = null;  	double			gps_start_altitude = AltosLib.MISSING; +	AltosFlightSeries	series;  	AltosFlightStats	stats; +	AltosCalData		cal_data;  	static final String[] kml_state_colors = {  		"FF000000",	// startup  		"FF000000",	// idle  		"FF000000",	// pad  		"FF0000FF",	// boost +		"FF8040FF",	// coast  		"FF4080FF",	// fast -		"FF00FFFF",	// coast -		"FFFF0000",	// drogue +		"FF00FFFF",	// drogue  		"FF00FF00",	// main  		"FF000000",	// landed  		"FFFFFFFF",	// invalid @@ -60,85 +62,169 @@ public class AltosKML implements AltosWriter {  		return kml_state_colors[state];  	} +	static final String[] kml_style_colors = { +		"FF0000FF",	// baro +		"FFFF0000",	// gps +	}; + +	static String style_color(int style) { +		if (style < 0 || kml_style_colors.length <= style) +			return kml_style_colors[0]; +		return kml_style_colors[style]; +	} +  	static final String kml_header_start =  		"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +  		"<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +  		"<Document>\n" +  		"  <name>AO Flight#%d S/N: %03d</name>\n" + -		"  <description>\n"; +		"  <Snippet maxLines=\"8\">\n"; +  	static final String kml_header_end = -		"  </description>\n" + -		"  <open>0</open>\n"; - -	static final String kml_style_start = -		"  <Style id=\"ao-flightstate-%s\">\n" + -		"    <LineStyle><color>%s</color><width>4</width></LineStyle>\n" + -		"    <BalloonStyle>\n" + -		"      <text>\n"; - -	static final String kml_style_end = -		"      </text>\n" + -		"    </BalloonStyle>\n" + -		"  </Style>\n"; - -	static final String kml_placemark_start = -		"  <Placemark>\n" + -		"    <name>%s</name>\n" + -		"    <styleUrl>#ao-flightstate-%s</styleUrl>\n" + -		"    <LineString>\n" + -		"      <tessellate>1</tessellate>\n" + -		"      <altitudeMode>absolute</altitudeMode>\n" + -		"      <coordinates>\n"; +		"  </Snippet>\n" + +		"  <open>1</open>\n"; + +	static final String kml_folder_start = +		"  <Folder>\n" + +		"    <name>%s</name>\n"; + +	static final String kml_path_style_start = +		"    <Style id=\"ao-style-%s\">\n" + +		"      <LineStyle><color>%s</color><width>8</width></LineStyle>\n" + +		"      <BalloonStyle>\n" + +		"        <text>\n"; + +	static final String kml_path_style_end = +		"        </text>\n" + +		"      </BalloonStyle>\n" + +		"    </Style>\n"; + +	static final String kml_point_style_start = +		"    <Style id=\"ao-style-%s\">\n" + +		"      <LabelStyle><color>%s</color></LabelStyle>\n" + +		"      <IconStyle><color>%s</color></IconStyle>\n" + +		"      <BalloonStyle>\n" + +		"        <text>\n"; + +	static final String kml_point_style_end = +		"        </text>\n" + +		"      </BalloonStyle>\n" + +		"    </Style>\n"; + +	static final String kml_path_start = +		"    <Placemark>\n" + +		"      <name>%s</name>\n" + +		"      <styleUrl>#ao-style-%s</styleUrl>\n" + +		"      <LineString>\n" + +		"        <tessellate>1</tessellate>\n" + +		"        <altitudeMode>absolute</altitudeMode>\n" + +		"        <coordinates>\n";  	static final String kml_coord_fmt = -	"        %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n"; +	"          %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n"; -	static final String kml_placemark_end = -		"      </coordinates>\n" + -		"    </LineString>\n" + -		"  </Placemark>\n"; +	static final String kml_path_end = +		"        </coordinates>\n" + +		"      </LineString>\n" + +		"    </Placemark>\n"; + +	static final String kml_point_start = +		"    <Placemark>\n" + +		"      <name>%s</name>\n" + +		"      <styleUrl>#ao-style-%s</styleUrl>\n" + +		"      <Point>\n" + +		"        <tessellate>1</tessellate>\n" + +		"        <altitudeMode>absolute</altitudeMode>\n" + +		"        <coordinates>\n"; + +	static final String kml_point_end = +		"        </coordinates>\n" + +		"      </Point>\n" + +		"    </Placemark>\n"; + +	static final String kml_folder_end = +		"  </Folder>\n";  	static final String kml_footer =  		"</Document>\n" +  		"</kml>\n"; -	void start (AltosCalData cal_data) { +	void start () {  		AltosGPS gps = cal_data.gps_pad;  		gps_start_altitude = cal_data.gps_pad_altitude;  		out.printf(kml_header_start, cal_data.flight, cal_data.serial); -		out.printf("Date:   %04d-%02d-%02d\n", +		out.printf("Product: %s\n", stats.product); +		out.printf("Firmware: %s\n", stats.firmware_version); +		out.printf("Date: %04d-%02d-%02d\n",  			   gps.year, gps.month, gps.day); -		out.printf("Time:     %2d:%02d:%02d\n", +		out.printf("Time: %2d:%02d:%02d\n",  			   gps.hour, gps.minute, gps.second); +		if (stats.max_height != AltosLib.MISSING) +			out.printf("Max baro height: %s\n", AltosConvert.height.show(6, stats.max_height)); +		if (stats.max_gps_height != AltosLib.MISSING) +			out.printf("Max GPS Height: %s\n", AltosConvert.height.show(6, stats.max_gps_height)); +		if (stats.max_speed != AltosLib.MISSING) +			out.printf("Max speed: %s\n", AltosConvert.speed.show(6, stats.max_speed)); +		if (stats.max_acceleration != AltosLib.MISSING) +			out.printf("Max accel: %s\n", AltosConvert.accel.show(6, stats.max_acceleration));  		out.printf("%s", kml_header_end);  	} -	boolean	started = false; +	void folder_start(String folder_name) { +		out.printf(kml_folder_start, folder_name); +	} -	void state_start(int state) { -		String	state_name = AltosLib.state_name(state); -		String	state_color = state_color(state); -		out.printf(kml_style_start, state_name, state_color); -		out.printf("State: %s\n", state_name); -		out.printf("Time: %6.2f s\n", stats.state_time[state]); -		out.printf("Average speed: %s\n", AltosConvert.speed.show(6, stats.state_speed[state])); -		out.printf("Average accel: %s\n", AltosConvert.accel.show(6, stats.state_accel[state])); -		out.printf("%s", kml_style_end); -		out.printf(kml_placemark_start, state_name, state_name); +	void folder_end() { +		out.printf(kml_folder_end);  	} -	void state_end() { -		out.printf("%s", kml_placemark_end); +	void path_style_start(String style, String color) { +		out.printf(kml_path_style_start, style, color);  	} -	void coord(double time, AltosGPS gps, int state, double height) { -		double		altitude; +	void path_style_end() { +		out.printf(kml_path_style_end); +	} + +	void point_style_start(String style, String color) { +		out.printf(kml_point_style_start, style, color, color); +	} + +	void point_style_end() { +		out.printf(kml_point_style_end); +	} -		if (height != AltosLib.MISSING) -			altitude = height + gps_start_altitude; -		else -			altitude = gps.alt; +	void path_start(String name, String style) { +		out.printf(kml_path_start, name, style); +	} + +	void path_end() { +		out.printf(kml_path_end); +	} + +	void point_start(String name, String style) { +		out.printf(kml_point_start, name, style); +	} + +	void point_end() { +		out.printf(kml_point_end); +	} + +	boolean	started = false; + +	private double baro_altitude(AltosFlightSeries series, double time) { +		double height = series.value(AltosFlightSeries.height_name, time); + +		if (height == AltosLib.MISSING) +			return AltosLib.MISSING; +		if (cal_data.gps_pad_altitude == AltosLib.MISSING) +			return AltosLib.MISSING; + +		return height + cal_data.gps_pad_altitude; +	} + +	void coord(double time, AltosGPS gps, double altitude) {  		out.printf(kml_coord_fmt,  			   gps.lon, gps.lat,  			   altitude, (double) gps.alt, @@ -150,48 +236,103 @@ public class AltosKML implements AltosWriter {  	}  	public void close() { -		if (prev != null) { -			state_end(); -			end(); -			prev = null; -		}  		if (out != null) {  			out.close();  			out = null;  		}  	} -	public void write(AltosGPSTimeValue gtv, AltosCalData cal_data, int state, double height) { -		AltosGPS gps = gtv.gps; +	public void write(AltosGPS gps, double alt) +	{  		if (gps.lat == AltosLib.MISSING)  			return;  		if (gps.lon == AltosLib.MISSING)  			return; -		if (state != flight_state) { -			flight_state = state; -			if (prev != null) { -				coord(gtv.time, gps, state, height); -				state_end(); -			} -			state_start(state); +		if (alt == AltosLib.MISSING) { +			alt = cal_data.gps_pad_altitude; +			if (alt == AltosLib.MISSING) +				return;  		} -		coord(0, gps, state, height); +		coord(0, gps, alt);  		prev = gps;  	} -	private int state(AltosFlightSeries series, double time) { -		return (int) series.value_before(AltosFlightSeries.state_name, time); -	} +	public void write_point(AltosTimeValue tv, boolean is_gps) { +		int		state = (int) tv.value; +		String		style_prefix = is_gps ? "gps-" : "baro-"; +		String		state_name = AltosLib.state_name(state); +		String		state_label = AltosLib.state_name_capital(state); +		String		style_name = style_prefix + state_name; +		String		folder_name = is_gps ? "GPS" : "Baro"; +		String		full_name = state_label + " (" + folder_name + ")"; +		AltosGPS	gps = series.gps_before(tv.time); +		double		altitude = is_gps ? gps.alt : baro_altitude(series, tv.time); -	private double height(AltosFlightSeries series, double time) { -		return series.value(AltosFlightSeries.height_name, time); +		point_style_start(style_name, state_color(state)); +		out.printf("%s\n", full_name); +		switch (state) { +		case AltosLib.ao_flight_boost: +			out.printf("Max accel %s\n", AltosConvert.accel.show(6, stats.max_acceleration)); +			out.printf("Max speed %s\n", AltosConvert.speed.show(6, stats.max_speed)); +			break; +		case AltosLib.ao_flight_coast: +		case AltosLib.ao_flight_fast: +			out.printf("Entry speed %s\n", AltosConvert.speed.show(6, stats.state_enter_speed[state])); +			out.printf("Entry height %s\n", AltosConvert.height.show(6, altitude - cal_data.gps_pad_altitude)); +			break; +		case AltosLib.ao_flight_drogue: +			out.printf("Max height %s\n", AltosConvert.height.show(6, is_gps ? stats.max_gps_height : stats.max_height)); +			out.printf("Average descent rate %s\n", AltosConvert.speed.show(6, -stats.state_speed[state])); +			break; +		case AltosLib.ao_flight_main: +			out.printf("Entry speed %s\n", AltosConvert.speed.show(6, -stats.state_enter_speed[state])); +			out.printf("Entry height %s\n", AltosConvert.height.show(6, altitude - cal_data.gps_pad_altitude)); +			out.printf("Average descent rate %s\n", AltosConvert.speed.show(6, -stats.state_speed[state])); +			break; +		case AltosLib.ao_flight_landed: +			out.printf("Landing speed %s\n", AltosConvert.speed.show(6, -stats.state_enter_speed[state])); +			break; +		} +		point_style_end(); +		point_start(full_name, style_name); +		gps = series.gps_before(tv.time); +		write(gps, altitude); +		point_end();  	}  	public void write(AltosFlightSeries series) { +		this.series = series; +		series.finish();  		stats = new AltosFlightStats(series); -		start(series.cal_data()); +		cal_data = series.cal_data(); +		start(); +		folder_start("Barometric Altitude"); +		path_style_start("baro", style_color(0)); +		out.printf("Barometric Altitude\n"); +		out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_height)); +		path_style_end(); +		path_start("Barometric Altitude", "baro");  		for (AltosGPSTimeValue gtv : series.gps_series) -			write(gtv, series.cal_data(), state(series, gtv.time), height(series, gtv.time)); +			write(gtv.gps, baro_altitude(series, gtv.time)); +		path_end(); +		for (AltosTimeValue tv : series.state_series) { +			write_point(tv, false); +		} +		folder_end(); +		folder_start("GPS Altitude"); +		path_style_start("gps", style_color(1)); +		out.printf("GPS Altitude"); +		out.printf("Max height: %s\n", AltosConvert.height.show(6, stats.max_gps_height)); +		path_style_end(); +		path_start("GPS Altitude", "gps"); +		for (AltosGPSTimeValue gtv : series.gps_series) +			write(gtv.gps, gtv.gps.alt); +		path_end(); +		for (AltosTimeValue tv : series.state_series) { +			write_point(tv, true); +		} +		folder_end(); +		end();  	}  	public AltosKML(File in_name) throws FileNotFoundException { | 
