summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBdale Garbee <bdale@gag.com>2009-09-06 17:34:08 -0600
committerBdale Garbee <bdale@gag.com>2009-09-06 17:34:08 -0600
commitd256f8204e9fce53ae4309562bb4c0cde1fae43e (patch)
tree76d36267c4a551f8aa570c07c045a682c73a4e5c
parent0fc344dfc031a8b1eef7cc40efb1d5ba7782269d (diff)
parent32d3536706324808df6cd02248a236302b831571 (diff)
Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
-rw-r--r--ao-tools/ao-postflight/Makefile.am4
-rw-r--r--ao-tools/ao-postflight/ao-postflight.c132
-rw-r--r--ao-tools/lib/cc-analyse.c174
-rw-r--r--ao-tools/lib/cc-process.c18
-rw-r--r--ao-tools/lib/cc.h29
-rw-r--r--configure.ac2
6 files changed, 318 insertions, 41 deletions
diff --git a/ao-tools/ao-postflight/Makefile.am b/ao-tools/ao-postflight/Makefile.am
index 301ac454..589d164a 100644
--- a/ao-tools/ao-postflight/Makefile.am
+++ b/ao-tools/ao-postflight/Makefile.am
@@ -1,11 +1,11 @@
bin_PROGRAMS=ao-postflight
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_CFLAGS)
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) $(GNOME_CFLAGS) $(PLPLOT_CFLAGS)
AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
ao_postflight_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
-ao_postflight_LDADD=$(AO_POSTFLIGHT_LIBS) $(LIBUSB_LIBS) $(GNOME_LIBS)
+ao_postflight_LDADD=$(AO_POSTFLIGHT_LIBS) $(LIBUSB_LIBS) $(GNOME_LIBS) $(PLPLOT_LIBS)
ao_postflight_SOURCES = ao-postflight.c
diff --git a/ao-tools/ao-postflight/ao-postflight.c b/ao-tools/ao-postflight/ao-postflight.c
index c1e4d800..bc6638e9 100644
--- a/ao-tools/ao-postflight/ao-postflight.c
+++ b/ao-tools/ao-postflight/ao-postflight.c
@@ -24,8 +24,7 @@
#include <getopt.h>
#include "cc-usb.h"
#include "cc.h"
-
-#define NUM_BLOCK 512
+#include <plplot/plplot.h>
static const char *state_names[] = {
"startup",
@@ -40,12 +39,75 @@ static const char *state_names[] = {
"invalid"
};
-void
-analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file)
+static void
+plot_perioddata(struct cc_perioddata *d, char *axis_label, char *plot_label,
+ double min_time, double max_time)
+{
+ double *times;
+ double ymin, ymax;
+ int ymin_i, ymax_i;
+ int i;
+ int start, stop;
+
+ if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
+ return;
+
+ times = calloc(stop - start + 1, sizeof (double));
+ for (i = start; i <= stop; i++)
+ times[i-start] = i * d->step / 100.0;
+
+ ymin_i = cc_perioddata_min(d, min_time, max_time);
+ ymax_i = cc_perioddata_max(d, min_time, max_time);
+ ymin = d->data[ymin_i];
+ ymax = d->data[ymax_i];
+ plenv(times[0], times[stop-start],
+ ymin, ymax, 0, 2);
+ plcol0(1);
+ pllab("Time", axis_label, plot_label);
+ plline(stop - start + 1, times, d->data + start);
+}
+
+static struct cc_perioddata *
+merge_data(struct cc_perioddata *first, struct cc_perioddata *last, double split_time)
+{
+ int i;
+ struct cc_perioddata *pd;
+ int num;
+ double start_time, stop_time;
+ double t;
+
+ pd = calloc(1, sizeof (struct cc_perioddata));
+ start_time = first->start;
+ stop_time = last->start + last->step * last->num;
+ num = (stop_time - start_time) / first->step;
+ pd->num = num;
+ pd->data = calloc(num, sizeof (double));
+ pd->start = first->start;
+ pd->step = first->step;
+ for (i = 0; i < num; i++) {
+ t = pd->start + i * pd->step;
+ if (t <= split_time) {
+ pd->data[i] = first->data[i];
+ } else {
+ int j;
+
+ j = (t - last->start) / last->step;
+ if (j < 0 || j >= last->num)
+ pd->data[i] = 0;
+ else
+ pd->data[i] = last->data[j];
+ }
+ }
+ return pd;
+}
+
+static void
+analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file, char *plot_name)
{
double height;
double accel;
double speed;
+ double avg_speed;
double boost_start, boost_stop;
double min_pres;
int i;
@@ -129,18 +191,24 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file)
if (cooked) {
if (state < ao_flight_drogue) {
- speed_i = cc_perioddata_max(&cooked->accel_speed, state_start, state_stop);
+ speed_i = cc_perioddata_max_mag(&cooked->accel_speed, state_start, state_stop);
if (speed_i >= 0)
speed = cooked->accel_speed.data[speed_i];
+ avg_speed = cc_perioddata_average(&cooked->accel_speed, state_start, state_stop);
} else {
- speed_i = cc_perioddata_max(&cooked->pres_speed, state_start, state_stop);
+ speed_i = cc_perioddata_max_mag(&cooked->pres_speed, state_start, state_stop);
if (speed_i >= 0)
speed = cooked->pres_speed.data[speed_i];
+ avg_speed = cc_perioddata_average(&cooked->pres_speed, state_start, state_stop);
}
if (speed_i >= 0)
+ {
fprintf(summary_file, "\tMax speed: %9.2fm/s %9.2fft/s %9.2fs\n",
speed, speed * 100 / 2.4 / 12.0,
(cooked->accel_speed.start + speed_i * cooked->accel_speed.step - boost_start) / 100.0);
+ fprintf(summary_file, "\tAvg speed: %9.2fm/s %9.2fft/s\n",
+ avg_speed, avg_speed * 100 / 2.4 / 12.0);
+ }
}
pres_i = cc_timedata_min(&f->pres, state_start, state_stop);
if (pres_i >= 0)
@@ -154,16 +222,10 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file)
}
}
if (cooked && detail_file) {
- double apogee_time;
double max_height = 0;
int i;
+ double *times;
- for (i = 0; i < cooked->pres_pos.num; i++) {
- if (cooked->pres_pos.data[i] > max_height) {
- max_height = cooked->pres_pos.data[i];
- apogee_time = cooked->pres_pos.start + cooked->pres_pos.step * i;
- }
- }
fprintf(detail_file, "%9s %9s %9s %9s\n",
"time", "height", "speed", "accel");
for (i = 0; i < cooked->pres_pos.num; i++) {
@@ -171,7 +233,7 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file)
double accel = cooked->accel_accel.data[i];
double pos = cooked->pres_pos.data[i];
double speed;
- if (cooked->pres_pos.start + cooked->pres_pos.step * i < apogee_time)
+ if (cooked->pres_pos.start + cooked->pres_pos.step * i < apogee)
speed = cooked->accel_speed.data[i];
else
speed = cooked->pres_speed.data[i];
@@ -179,17 +241,41 @@ analyse_flight(struct cc_flightraw *f, FILE *summary_file, FILE *detail_file)
time, pos, speed, accel);
}
}
+ if (cooked && plot_name) {
+ struct cc_perioddata *speed;
+ plsdev("svgcairo");
+ plsfnam(plot_name);
+#define PLOT_DPI 96
+ plspage(PLOT_DPI, PLOT_DPI, 8 * PLOT_DPI, 8 * PLOT_DPI, 0, 0);
+ plscolbg(0xff, 0xff, 0xff);
+ plscol0(1,0,0,0);
+ 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);
+ free(speed->data);
+ free(speed);
+ plend();
+ }
+ if (cooked)
+ cc_flightcooked_free(cooked);
}
static const struct option options[] = {
- { .name = "summary", .has_arg = 1, .val = 'S' },
- { .name = "detail", .has_arg = 1, .val = 'D' },
+ { .name = "summary", .has_arg = 1, .val = 's' },
+ { .name = "detail", .has_arg = 1, .val = 'd' },
+ { .name = "plot", .has_arg = 1, .val = 'p' },
{ 0, 0, 0, 0},
};
static void usage(char *program)
{
- fprintf(stderr, "usage: %s [--summary=<summary-file>] [--detail=<detail-file] {flight-log} ...\n", program);
+ fprintf(stderr, "usage: %s [--summary=<summary-file>] [--detail=<detail-file] [--plot=<plot-file>] {flight-log} ...\n", program);
exit(1);
}
@@ -206,15 +292,19 @@ main (int argc, char **argv)
int serial;
char *s;
char *summary_name = NULL, *detail_name = NULL;
+ char *plot_name = NULL;
- while ((c = getopt_long(argc, argv, "S:D:", options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "s:d:p:", options, NULL)) != -1) {
switch (c) {
- case 'S':
+ case 's':
summary_name = optarg;
break;
- case 'D':
+ case 'd':
detail_name = optarg;
break;
+ case 'p':
+ plot_name = optarg;
+ break;
default:
usage(argv[0]);
break;
@@ -260,7 +350,7 @@ main (int argc, char **argv)
}
if (!raw->serial)
raw->serial = serial;
- analyse_flight(raw, summary_file, detail_file);
+ analyse_flight(raw, summary_file, detail_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 0e020115..cdb16f02 100644
--- a/ao-tools/lib/cc-analyse.c
+++ b/ao-tools/lib/cc-analyse.c
@@ -39,6 +39,26 @@ cc_timedata_min(struct cc_timedata *d, double min_time, double max_time)
}
int
+cc_timedata_min_mag(struct cc_timedata *d, double min_time, double max_time)
+{
+ int i;
+ int set = 0;
+ int min_i = -1;
+ double min;
+
+ if (d->num == 0)
+ return -1;
+ for (i = 0; i < d->num; i++)
+ if (min_time <= d->data[i].time && d->data[i].time <= max_time)
+ if (!set || fabs(d->data[i].value) < min) {
+ min_i = i;
+ min = fabs(d->data[i].value);
+ set = 1;
+ }
+ return min_i;
+}
+
+int
cc_timedata_max(struct cc_timedata *d, double min_time, double max_time)
{
int i;
@@ -59,22 +79,80 @@ cc_timedata_max(struct cc_timedata *d, double min_time, double max_time)
}
int
+cc_timedata_max_mag(struct cc_timedata *d, double min_time, double max_time)
+{
+ int i;
+ double max;
+ int max_i = -1;
+ int set = 0;
+
+ if (d->num == 0)
+ return -1;
+ for (i = 0; i < d->num; i++)
+ if (min_time <= d->data[i].time && d->data[i].time <= max_time)
+ if (!set || fabs(d->data[i].value) > max) {
+ max_i = i;
+ max = fabs(d->data[i].value);
+ set = 1;
+ }
+ return max_i;
+}
+
+double
+cc_timedata_average(struct cc_timedata *td, double start_time, double stop_time)
+{
+ int i;
+ double prev_time;
+ double next_time;
+ double interval;
+ double sum = 0.0;
+ double period = 0.0;
+
+ prev_time = start_time;
+ for (i = 0; i < td->num; i++) {
+ if (start_time <= td->data[i].time && td->data[i].time <= stop_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;
+ sum += td->data[i].value * interval;
+ period += interval;
+ prev_time = next_time;
+ }
+ }
+ return sum / period;
+}
+
+int
+cc_perioddata_limits(struct cc_perioddata *d, double min_time, double max_time, int *start, int *stop)
+{
+ double start_d, stop_d;
+
+ if (d->num == 0)
+ return 0;
+ start_d = ceil((min_time - d->start) / d->step);
+ if (start_d < 0)
+ start_d = 0;
+ stop_d = floor((max_time - d->start) / d->step);
+ if (stop_d >= d->num)
+ stop_d = d->num - 1;
+ if (stop_d < start_d)
+ return 0;
+ *start = (int) start_d;
+ *stop = (int) stop_d;
+ return 1;
+}
+
+int
cc_perioddata_min(struct cc_perioddata *d, double min_time, double max_time)
{
- int start, stop;
int i;
double min;
int min_i;
+ int start, stop;
- if (d->num == 0)
- return -1;
- start = (int) ceil((min_time - d->start) / d->step);
- if (start < 0)
- start = 0;
- stop = (int) floor((max_time - d->start) / d->step);
- if (stop >= d->num)
- stop = d->num - 1;
- if (stop < start)
+ if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
return -1;
min = d->data[start];
min_i = start;
@@ -87,6 +165,26 @@ cc_perioddata_min(struct cc_perioddata *d, double min_time, double max_time)
}
int
+cc_perioddata_min_mag(struct cc_perioddata *d, double min_time, double max_time)
+{
+ int start, stop;
+ int i;
+ double min;
+ int min_i;
+
+ if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
+ return -1;
+ min = d->data[start];
+ min_i = start;
+ for (i = start + 1; i <= stop; i++)
+ if (fabs(d->data[i]) < min) {
+ min = fabs(d->data[i]);
+ min_i = i;
+ }
+ return min_i;
+}
+
+int
cc_perioddata_max(struct cc_perioddata *d, double min_time, double max_time)
{
int start, stop;
@@ -94,15 +192,27 @@ cc_perioddata_max(struct cc_perioddata *d, double min_time, double max_time)
double max;
int max_i;
- if (d->num == 0)
+ if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
return -1;
- start = (int) ceil((min_time - d->start) / d->step);
- if (start < 0)
- start = 0;
- stop = (int) floor((max_time - d->start) / d->step);
- if (stop >= d->num)
- stop = d->num - 1;
- if (stop < start)
+ max = d->data[start];
+ max_i = start;
+ for (i = start + 1; i <= stop; i++)
+ if (d->data[i] > max) {
+ max = d->data[i];
+ max_i = i;
+ }
+ return max_i;
+}
+
+int
+cc_perioddata_max_mag(struct cc_perioddata *d, double min_time, double max_time)
+{
+ int start, stop;
+ int i;
+ double max;
+ int max_i;
+
+ if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
return -1;
max = d->data[start];
max_i = start;
@@ -113,3 +223,31 @@ cc_perioddata_max(struct cc_perioddata *d, double min_time, double max_time)
}
return max_i;
}
+
+double
+cc_perioddata_average(struct cc_perioddata *d, double min_time, double max_time)
+{
+ int start, stop;
+ int i;
+ double sum = 0.0;
+
+ if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
+ return 0.0;
+ for (i = start; i <= stop; i++)
+ sum += d->data[i];
+ return sum / (stop - start + 1);
+}
+
+double
+cc_perioddata_average_mag(struct cc_perioddata *d, double min_time, double max_time)
+{
+ int start, stop;
+ int i;
+ double sum = 0.0;
+
+ if (!cc_perioddata_limits(d, min_time, max_time, &start, &stop))
+ return 0.0;
+ for (i = start; i <= stop; i++)
+ sum += fabs(d->data[i]);
+ return sum / (stop - start + 1);
+}
diff --git a/ao-tools/lib/cc-process.c b/ao-tools/lib/cc-process.c
index e906b635..469ad2f2 100644
--- a/ao-tools/lib/cc-process.c
+++ b/ao-tools/lib/cc-process.c
@@ -138,3 +138,21 @@ cc_flight_cook(struct cc_flightraw *raw)
cooked->state.time_offset = raw->state.time_offset;
return cooked;
}
+
+#define if_free(x) ((x) ? free(x) : (void) 0)
+
+void
+cc_flightcooked_free(struct cc_flightcooked *cooked)
+{
+ if_free(cooked->accel_accel.data);
+ if_free(cooked->accel_speed.data);
+ if_free(cooked->accel_pos.data);
+ if_free(cooked->pres_pos.data);
+ if_free(cooked->pres_speed.data);
+ if_free(cooked->pres_accel.data);
+ if_free(cooked->gps_lat.data);
+ if_free(cooked->gps_lon.data);
+ if_free(cooked->gps_alt.data);
+ if_free(cooked->state.data);
+ free(cooked);
+}
diff --git a/ao-tools/lib/cc.h b/ao-tools/lib/cc.h
index 356794e0..4e9aadc4 100644
--- a/ao-tools/lib/cc.h
+++ b/ao-tools/lib/cc.h
@@ -266,14 +266,41 @@ int
cc_timedata_min(struct cc_timedata *d, double min_time, double max_time);
int
+cc_timedata_min_mag(struct cc_timedata *d, double min_time, double max_time);
+
+int
cc_timedata_max(struct cc_timedata *d, double min_time, double max_time);
int
+cc_timedata_max_mag(struct cc_timedata *d, double min_time, double max_time);
+
+double
+cc_timedata_average(struct cc_timedata *d, double min_time, double max_time);
+
+double
+cc_timedata_average_mag(struct cc_timedata *d, double min_time, double max_time);
+
+int
+cc_perioddata_limits(struct cc_perioddata *d, double min_time, double max_time, int *start, int *stop);
+
+int
cc_perioddata_min(struct cc_perioddata *d, double min_time, double max_time);
int
+cc_perioddata_min_mag(struct cc_perioddata *d, double min_time, double max_time);
+
+int
cc_perioddata_max(struct cc_perioddata *d, double min_time, double max_time);
+int
+cc_perioddata_max_mag(struct cc_perioddata *d, double min_time, double max_time);
+
+double
+cc_perioddata_average(struct cc_perioddata *d, double min_time, double max_time);
+
+double
+cc_perioddata_average_mag(struct cc_perioddata *d, double min_time, double max_time);
+
double *
cc_low_pass(double *data, int data_len, double omega_pass, double omega_stop, double error);
@@ -295,5 +322,7 @@ cc_perioddata_differentiate(struct cc_perioddata *i);
struct cc_flightcooked *
cc_flight_cook(struct cc_flightraw *raw);
+void
+cc_flightcooked_free(struct cc_flightcooked *cooked);
#endif /* _CC_H_ */
diff --git a/configure.ac b/configure.ac
index c668df04..6265c34e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -71,6 +71,8 @@ PKG_CHECK_MODULES([LIBUSB], [libusb-1.0])
PKG_CHECK_MODULES([ALSA], [alsa])
+PKG_CHECK_MODULES([PLPLOT], [plplotd-gnome2])
+
AC_OUTPUT([
Makefile
ao-tools/Makefile