Color plots, integrate only flight portion of data.
authorKeith Packard <keithp@keithp.com>
Mon, 7 Sep 2009 03:26:17 +0000 (20:26 -0700)
committerKeith Packard <keithp@keithp.com>
Mon, 7 Sep 2009 03:26:17 +0000 (20:26 -0700)
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 <keithp@keithp.com>
ao-tools/ao-postflight/ao-postflight.1
ao-tools/ao-postflight/ao-postflight.c
ao-tools/lib/cc-analyse.c
ao-tools/lib/cc-integrate.c
ao-tools/lib/cc-period.c
ao-tools/lib/cc-process.c
ao-tools/lib/cc.h

index ac1c18a4243c766c32ddd0ef3cad751eec76ad58..eca4bb344175a35f097a21dfee3fc46ce58d028c 100644 (file)
@@ -23,15 +23,29 @@ ao-postflight \- Analyse a flight log (either telemetry or eeprom)
 .B "ao-postflight"
 [\-s <summary-file>]
 [\--summary=<summary-file>]
-[\-d <detail-file]
+[\-d <detail-file>]
 [\--detail=<detail-file>]
+[\-r <raw-file>]
+[\--raw=<raw-file>]
 [\-p <plot-file>]
 [\--plot=<plot-file>]
 {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
index 4ca39c2448a2483359643776afecede920655dea..ded2f3c2764dcb3a8b6406e80b076159d4a46611 100644 (file)
@@ -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=<summary-file>] [-s <summary-file>] [--detail=<detail-file] [-d <detail-file>] [--plot=<plot-file> -p <plot-file>] {flight-log} ...\n", program);
+       fprintf(stderr, "usage: %s\n"
+               "\t[--summary=<summary-file>] [-s <summary-file>]\n"
+               "\t[--detail=<detail-file] [-d <detail-file>]\n"
+               "\t[--raw=<raw-file> -r <raw-file]\n"
+               "\t[--plot=<plot-file> -p <plot-file>]\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;
index cdb16f02fc6b619593cbd4c027a7454756ede714..27c416a6387056d01a81c16bf11523ce8a91fbea 100644 (file)
 #include "cc.h"
 #include <math.h>
 
+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)
 {
index f9793dcdb3a3c3a5377a939659039a19d833d8b6..ba50761b257a4dc68333135af313f3c39860c9c8 100644 (file)
@@ -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;
index c74cf9dcff638bcdaaaf3b579b08c69b2ec1e96a..2a4e59521907a36d621199c2e1a6a6e19d5f8072 100644 (file)
 
 #include "cc.h"
 #include <stdlib.h>
+#include <math.h>
 
 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;
 }
index 469ad2f2c9120bd6575fafe64973fadedfb1ed0b..5c1acc6bd203384028b737596a4545d4860a72c7 100644 (file)
@@ -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);
 }
index 4e9aadc4f90ea436307ba7ede76d598eb8f72669..0122695889b022d05ed63617318ea41bff8a6427 100644 (file)
@@ -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);