diff options
| -rw-r--r-- | ao-tools/ao-postflight/ao-postflight.1 | 22 | ||||
| -rw-r--r-- | ao-tools/ao-postflight/ao-postflight.c | 118 | ||||
| -rw-r--r-- | ao-tools/lib/cc-analyse.c | 14 | ||||
| -rw-r--r-- | ao-tools/lib/cc-integrate.c | 21 | ||||
| -rw-r--r-- | ao-tools/lib/cc-period.c | 26 | ||||
| -rw-r--r-- | ao-tools/lib/cc-process.c | 20 | ||||
| -rw-r--r-- | ao-tools/lib/cc.h | 12 | 
7 files changed, 180 insertions, 53 deletions
| 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-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 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=<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; 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 <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)  { 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 <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;  } 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); | 
