diff options
| -rw-r--r-- | ao-tools/ao-postflight/Makefile.am | 4 | ||||
| -rw-r--r-- | ao-tools/ao-postflight/ao-postflight.c | 132 | ||||
| -rw-r--r-- | ao-tools/lib/cc-analyse.c | 174 | ||||
| -rw-r--r-- | ao-tools/lib/cc-process.c | 18 | ||||
| -rw-r--r-- | ao-tools/lib/cc.h | 29 | ||||
| -rw-r--r-- | configure.ac | 2 | 
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 | 
