From 730ee7bf91f607ece42c010a10c53d0013492b96 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 4 Oct 2017 13:42:16 -0700 Subject: [PATCH] altoslib: Adapt KML output to make TRA record people happier Provide two paths, one using GPS data the other baro. Replace separate path segments for each state with markers so that the path is a single unit, able to be displayed in the elevation profile widget. Signed-off-by: Keith Packard --- altoslib/AltosFlightStats.java | 7 + 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 = "\n" + "\n" + "\n" + " AO Flight#%d S/N: %03d\n" + - " \n"; + " \n"; + static final String kml_header_end = - " \n" + - " 0\n"; - - static final String kml_style_start = - " \n"; - - static final String kml_placemark_start = - " \n" + - " %s\n" + - " #ao-flightstate-%s\n" + - " \n" + - " 1\n" + - " absolute\n" + - " \n"; + " \n" + + " 1\n"; + + static final String kml_folder_start = + " \n" + + " %s\n"; + + static final String kml_path_style_start = + " \n"; + + static final String kml_point_style_start = + " \n"; + + static final String kml_path_start = + " \n" + + " %s\n" + + " #ao-style-%s\n" + + " \n" + + " 1\n" + + " absolute\n" + + " \n"; static final String kml_coord_fmt = - " %.7f,%.7f,%.7f \n"; + " %.7f,%.7f,%.7f \n"; - static final String kml_placemark_end = - " \n" + - " \n" + - " \n"; + static final String kml_path_end = + " \n" + + " \n" + + " \n"; + + static final String kml_point_start = + " \n" + + " %s\n" + + " #ao-style-%s\n" + + " \n" + + " 1\n" + + " absolute\n" + + " \n"; + + static final String kml_point_end = + " \n" + + " \n" + + " \n"; + + static final String kml_folder_end = + " \n"; static final String kml_footer = "\n" + "\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 { -- 2.30.2