From: Keith Packard Date: Mon, 7 Sep 2009 03:26:17 +0000 (-0700) Subject: Color plots, integrate only flight portion of data. X-Git-Tag: debian/0.5+77+gc57bd7f~8^2~3 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=932f1539b38567e565fd484171c13539b1467308 Color plots, integrate only flight portion of data. Telemetry files have piles of pad data which shouldn't be integrated into the velocity data as it tends to generate huge values from the noise of the sensor. Also make the data lines colored to keep them visually distinct from the rest of the plot image. Signed-off-by: Keith Packard --- diff --git a/ao-tools/ao-postflight/ao-postflight.1 b/ao-tools/ao-postflight/ao-postflight.1 index ac1c18a4..eca4bb34 100644 --- a/ao-tools/ao-postflight/ao-postflight.1 +++ b/ao-tools/ao-postflight/ao-postflight.1 @@ -23,15 +23,29 @@ ao-postflight \- Analyse a flight log (either telemetry or eeprom) .B "ao-postflight" [\-s ] [\--summary=] -[\-d ] [\--detail=] +[\-r ] +[\--raw=] [\-p ] [\--plot=] {flight.eeprom|flight.telem} .SH DESCRIPTION .I ao-postflight -reads the specified flight log and produces a summary of the flight on -stdout or to the specified file along with an optional .svg format -plot and detailed table of time/height/speed/accel. +reads the specified flight log and produces several different kinds of +output. +.IP Summary +By default, summary information is shown on stdout. With the --summary +option, it can be redirected to a file. +.IP Detail +When requested with the --detail option, a filtered version of the +flight position, speed and acceleration are written to the specified +file. +.IP Raw +The --raw option writes the unfiltered, but converted acceleration +and height data to the specified file. +.IP Plot +The --plot option writes plots of height, speed and acceleration to +the specified file in .svg format .SH AUTHOR Keith Packard diff --git a/ao-tools/ao-postflight/ao-postflight.c b/ao-tools/ao-postflight/ao-postflight.c index 4ca39c24..ded2f3c2 100644 --- a/ao-tools/ao-postflight/ao-postflight.c +++ b/ao-tools/ao-postflight/ao-postflight.c @@ -39,9 +39,19 @@ static const char *state_names[] = { "invalid" }; +static int plot_colors[3][3] = { + { 0, 0x90, 0 }, /* height */ + { 0xa0, 0, 0 }, /* speed */ + { 0, 0, 0xc0 }, /* accel */ +}; + +#define PLOT_HEIGHT 0 +#define PLOT_SPEED 1 +#define PLOT_ACCEL 2 + static void plot_perioddata(struct cc_perioddata *d, char *axis_label, char *plot_label, - double min_time, double max_time) + double min_time, double max_time, int plot_type) { double *times; double ymin, ymax; @@ -60,11 +70,58 @@ plot_perioddata(struct cc_perioddata *d, char *axis_label, char *plot_label, ymax_i = cc_perioddata_max(d, min_time, max_time); ymin = d->data[ymin_i]; ymax = d->data[ymax_i]; + plscol0(1, 0, 0, 0); + plscol0(2, plot_colors[plot_type][0], plot_colors[plot_type][1], plot_colors[plot_type][2]); + plcol0(1); plenv(times[0], times[stop-start], ymin, ymax, 0, 2); - plcol0(1); pllab("Time", axis_label, plot_label); + plcol0(2); plline(stop - start + 1, times, d->data + start); + free(times); +} + +static void +plot_timedata(struct cc_timedata *d, char *axis_label, char *plot_label, + double min_time, double max_time) +{ + double *times; + double *values; + double ymin, ymax; + int ymin_i, ymax_i; + int i; + int start = -1, stop = -1; + double start_time = 0, stop_time = 0; + int num; + + for (i = 0; i < d->num; i++) { + if (start < 0 && d->data[i].time >= min_time) { + start_time = d->data[i].time; + start = i; + } + if (d->data[i].time <= max_time) { + stop_time = d->data[i].time; + stop = i; + } + } + + times = calloc(stop - start + 1, sizeof (double)); + values = calloc(stop - start + 1, sizeof (double)); + + ymin_i = cc_timedata_min(d, min_time, max_time); + ymax_i = cc_timedata_max(d, min_time, max_time); + ymin = d->data[ymin_i].value; + ymax = d->data[ymax_i].value; + plcol0(1); + pllab("Time", axis_label, plot_label); + for (i = start; i <= stop; i++) { + times[i-start] = (d->data[i].time - start_time)/100.0; + values[i-start] = d->data[i].value; + } + plenv(times[0], times[stop-start], ymin, ymax, 0, 2); + plline(stop - start + 1, times, values); + free(times); + free(values); } static struct cc_perioddata * @@ -102,7 +159,7 @@ merge_data(struct cc_perioddata *first, struct cc_perioddata *last, double split } static void -analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, char *plot_name) +analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, FILE *raw_file, char *plot_name) { double height; double accel; @@ -241,6 +298,17 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, ch time, pos, speed, accel); } } + if (raw_file) { + fprintf(raw_file, "%9s %9s %9s\n", + "time", "height", "accel"); + for (i = 0; i < cooked->pres.num; i++) { + double time = cooked->pres.data[i].time; + double pres = cooked->pres.data[i].value; + double accel = cooked->accel.data[i].value; + fprintf(raw_file, "%9.2f %9.2f %9.2f %9.2f\n", + time, pres, accel); + } + } if (cooked && plot_name) { struct cc_perioddata *speed; plsdev("svgcairo"); @@ -252,12 +320,12 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, ch plstar(2, 3); speed = merge_data(&cooked->accel_speed, &cooked->pres_speed, apogee); - plot_perioddata(&cooked->pres_pos, "meters", "Height", -1e10, 1e10); - plot_perioddata(&cooked->pres_pos, "meters", "Height", boost_start, apogee); - plot_perioddata(speed, "meters/second", "Speed", -1e10, 1e10); - plot_perioddata(speed, "meters/second", "Speed", boost_start, apogee); - plot_perioddata(&cooked->accel_accel, "meters/second²", "Acceleration", -1e10, 1e10); - plot_perioddata(&cooked->accel_accel, "meters/second²", "Acceleration", boost_start, apogee); + plot_perioddata(&cooked->pres_pos, "meters", "Height", -1e10, 1e10, PLOT_HEIGHT); + plot_perioddata(&cooked->pres_pos, "meters", "Height to Apogee", boost_start, apogee, PLOT_HEIGHT); + plot_perioddata(speed, "meters/second", "Speed", -1e10, 1e10, PLOT_SPEED); + plot_perioddata(speed, "meters/second", "Speed to Apogee", boost_start, apogee, PLOT_SPEED); + plot_perioddata(&cooked->accel_accel, "meters/second²", "Acceleration", -1e10, 1e10, PLOT_ACCEL); + plot_perioddata(&cooked->accel_accel, "meters/second²", "Acceleration to Apogee", boost_start, apogee, PLOT_ACCEL); free(speed->data); free(speed); plend(); @@ -270,12 +338,18 @@ static const struct option options[] = { { .name = "summary", .has_arg = 1, .val = 's' }, { .name = "detail", .has_arg = 1, .val = 'd' }, { .name = "plot", .has_arg = 1, .val = 'p' }, + { .name = "raw", .has_arg = 1, .val = 'r' }, { 0, 0, 0, 0}, }; static void usage(char *program) { - fprintf(stderr, "usage: %s [--summary=] [-s ] [--detail=] [--plot= -p ] {flight-log} ...\n", program); + fprintf(stderr, "usage: %s\n" + "\t[--summary=] [-s ]\n" + "\t[--detail=]\n" + "\t[--raw= -r -p ]\n" + "\t{flight-log} ...\n", program); exit(1); } @@ -283,18 +357,21 @@ int main (int argc, char **argv) { FILE *file; - FILE *summary_file; - FILE *detail_file; + FILE *summary_file = NULL; + FILE *detail_file = NULL; + FILE *raw_file = NULL; int i; int ret = 0; struct cc_flightraw *raw; int c; int serial; char *s; - char *summary_name = NULL, *detail_name = NULL; + char *summary_name = NULL; + char *detail_name = NULL; + char *raw_name = NULL; char *plot_name = NULL; - while ((c = getopt_long(argc, argv, "s:d:p:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "s:d:p:r:", options, NULL)) != -1) { switch (c) { case 's': summary_name = optarg; @@ -305,13 +382,15 @@ main (int argc, char **argv) case 'p': plot_name = optarg; break; + case 'r': + raw_name = optarg; + break; default: usage(argv[0]); break; } } summary_file = stdout; - detail_file = NULL; if (summary_name) { summary_file = fopen(summary_name, "w"); if (!summary_file) { @@ -330,6 +409,13 @@ main (int argc, char **argv) } } } + if (raw_name) { + raw_file = fopen (raw_name, "w"); + if (!raw_file) { + perror(raw_name); + exit(1); + } + } for (i = optind; i < argc; i++) { file = fopen(argv[i], "r"); if (!file) { @@ -350,7 +436,7 @@ main (int argc, char **argv) } if (!raw->serial) raw->serial = serial; - analyse_flight(raw, summary_file, detail_file, plot_name); + analyse_flight(raw, summary_file, detail_file, raw_file, plot_name); cc_flightraw_free(raw); } return ret; diff --git a/ao-tools/lib/cc-analyse.c b/ao-tools/lib/cc-analyse.c index cdb16f02..27c416a6 100644 --- a/ao-tools/lib/cc-analyse.c +++ b/ao-tools/lib/cc-analyse.c @@ -18,6 +18,20 @@ #include "cc.h" #include +void +cc_timedata_limits(struct cc_timedata *d, double min_time, double max_time, int *start, int *stop) +{ + int i; + + *start = -1; + for (i = 0; i < d->num; i++) { + if (*start < 0 && min_time <= d->data[i].time) + *start = i; + if (d->data[i].time <= max_time) + *stop = i; + } +} + int cc_timedata_min(struct cc_timedata *d, double min_time, double max_time) { diff --git a/ao-tools/lib/cc-integrate.c b/ao-tools/lib/cc-integrate.c index f9793dcd..ba50761b 100644 --- a/ao-tools/lib/cc-integrate.c +++ b/ao-tools/lib/cc-integrate.c @@ -37,24 +37,27 @@ cc_timedata_convert(struct cc_timedata *d, double (*f)(double v, double a), doub } struct cc_timedata * -cc_timedata_integrate(struct cc_timedata *d) +cc_timedata_integrate(struct cc_timedata *d, double min_time, double max_time) { struct cc_timedata *i; - int n; + int n, m; + int start, stop; + cc_timedata_limits(d, min_time, max_time, &start, &stop); i = calloc (1, sizeof (struct cc_timedata)); - i->num = d->num; - i->size = d->num; + i->num = stop - start + 1; + i->size = i->num; i->data = calloc (i->size, sizeof (struct cc_timedataelt)); - i->time_offset = d->time_offset; - for (n = 0; n < d->num; n++) { - i->data[n].time = d->data[n].time; + i->time_offset = d->data[start].time; + for (n = 0; n < i->num; n++) { + m = n + start; + i->data[n].time = d->data[m].time; if (n == 0) { i->data[n].value = 0; } else { i->data[n].value = i->data[n-1].value + - (d->data[n].value + d->data[n-1].value) / 2 * - ((d->data[n].time - d->data[n-1].time) / 100.0); + (d->data[m].value + d->data[m-1].value) / 2 * + ((d->data[m].time - d->data[m-1].time) / 100.0); } } return i; diff --git a/ao-tools/lib/cc-period.c b/ao-tools/lib/cc-period.c index c74cf9dc..2a4e5952 100644 --- a/ao-tools/lib/cc-period.c +++ b/ao-tools/lib/cc-period.c @@ -17,35 +17,27 @@ #include "cc.h" #include +#include struct cc_perioddata * cc_period_make(struct cc_timedata *td, double start_time, double stop_time) { int len = stop_time - start_time + 1; struct cc_perioddata *pd; - int i; - double prev_time; - double next_time; - double interval; + int i, j; + double t; pd = calloc(1, sizeof (struct cc_perioddata)); pd->start = start_time; pd->step = 1; pd->num = len; pd->data = calloc(len, sizeof(double)); - prev_time = start_time; - for (i = 0; i < td->num; i++) { - if (start_time <= td->data[i].time && td->data[i].time <= stop_time) { - int pos = td->data[i].time - start_time; - - if (i < td->num - 1 && td->data[i+1].time < stop_time) - next_time = (td->data[i].time + td->data[i+1].time) / 2.0; - else - next_time = stop_time; - interval = next_time - prev_time; - pd->data[pos] = td->data[i].value * interval; - prev_time = next_time; - } + j = 0; + for (i = 0; i < pd->num; i++) { + t = start_time + i * pd->step; + while (j < td->num - 1 && fabs(t - td->data[j].time) > fabs(t - td->data[j+1].time)) + j++; + pd->data[i] = td->data[j].value; } return pd; } diff --git a/ao-tools/lib/cc-process.c b/ao-tools/lib/cc-process.c index 469ad2f2..5c1acc6b 100644 --- a/ao-tools/lib/cc-process.c +++ b/ao-tools/lib/cc-process.c @@ -33,8 +33,6 @@ cook_timed(struct cc_timedata *td, struct cc_perioddata *pd, free (filtered); free (unfiltered->data); free (unfiltered); - free (td->data); - free (td); } static double @@ -93,11 +91,15 @@ cc_flight_cook(struct cc_flightraw *raw) } else { flight_stop = raw->accel.data[raw->accel.num-1].time; } + cooked->flight_start = flight_start; + cooked->flight_stop = flight_stop; /* Integrate the accelerometer data to get speed and position */ accel = cc_timedata_convert(&raw->accel, cc_accelerometer_to_acceleration, raw->ground_accel); - accel_speed = cc_timedata_integrate(accel); - accel_pos = cc_timedata_integrate(accel_speed); + cooked->accel = *accel; + free(accel); + accel_speed = cc_timedata_integrate(&cooked->accel, flight_start - 10, flight_stop); + accel_pos = cc_timedata_integrate(accel_speed, flight_start - 10, flight_stop); #define ACCEL_OMEGA_PASS (2 * M_PI * 5 / 100) #define ACCEL_OMEGA_STOP (2 * M_PI * 8 / 100) @@ -105,20 +107,24 @@ cc_flight_cook(struct cc_flightraw *raw) #define BARO_OMEGA_STOP (2 * M_PI * 1 / 100) #define FILTER_ERROR (1e-8) - cook_timed(accel, &cooked->accel_accel, + cook_timed(&cooked->accel, &cooked->accel_accel, flight_start, flight_stop, ACCEL_OMEGA_PASS, ACCEL_OMEGA_STOP, FILTER_ERROR); cook_timed(accel_speed, &cooked->accel_speed, flight_start, flight_stop, ACCEL_OMEGA_PASS, ACCEL_OMEGA_STOP, FILTER_ERROR); + free(accel_speed->data); free(accel_speed); cook_timed(accel_pos, &cooked->accel_pos, flight_start, flight_stop, ACCEL_OMEGA_PASS, ACCEL_OMEGA_STOP, FILTER_ERROR); + free(accel_pos->data); free(accel_pos); /* Filter the pressure data */ pres = cc_timedata_convert(&raw->pres, barometer_to_altitude, cc_barometer_to_altitude(raw->ground_pres)); - cook_timed(pres, &cooked->pres_pos, + cooked->pres = *pres; + free(pres); + cook_timed(&cooked->pres, &cooked->pres_pos, flight_start, flight_stop, BARO_OMEGA_PASS, BARO_OMEGA_STOP, FILTER_ERROR); /* differentiate twice to get to acceleration */ @@ -154,5 +160,7 @@ cc_flightcooked_free(struct cc_flightcooked *cooked) if_free(cooked->gps_lon.data); if_free(cooked->gps_alt.data); if_free(cooked->state.data); + if_free(cooked->accel.data); + if_free(cooked->pres.data); free(cooked); } diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h index 4e9aadc4..01226958 100644 --- a/ao-tools/lib/cc.h +++ b/ao-tools/lib/cc.h @@ -142,6 +142,9 @@ void cc_flightraw_free(struct cc_flightraw *raw); struct cc_flightcooked { + double flight_start; + double flight_stop; + struct cc_perioddata accel_accel; struct cc_perioddata accel_speed; struct cc_perioddata accel_pos; @@ -151,6 +154,10 @@ struct cc_flightcooked { struct cc_perioddata gps_lat; struct cc_perioddata gps_lon; struct cc_perioddata gps_alt; + + /* unfiltered, but converted */ + struct cc_timedata pres; + struct cc_timedata accel; struct cc_timedata state; }; @@ -262,6 +269,9 @@ cc_great_circle (double start_lat, double start_lon, double end_lat, double end_lon, double *dist, double *bearing); +void +cc_timedata_limits(struct cc_timedata *d, double min_time, double max_time, int *start, int *stop); + int cc_timedata_min(struct cc_timedata *d, double min_time, double max_time); @@ -314,7 +324,7 @@ struct cc_timedata * cc_timedata_convert(struct cc_timedata *d, double (*f)(double v, double a), double a); struct cc_timedata * -cc_timedata_integrate(struct cc_timedata *d); +cc_timedata_integrate(struct cc_timedata *d, double min_time, double max_time); struct cc_perioddata * cc_perioddata_differentiate(struct cc_perioddata *i);