ao-tools: Add ao-fakeflight
authorKeith Packard <keithp@keithp.com>
Mon, 14 Jul 2014 08:08:09 +0000 (01:08 -0700)
committerKeith Packard <keithp@keithp.com>
Mon, 18 Sep 2017 16:59:44 +0000 (09:59 -0700)
This generates a TeleMetrumV2 eeprom file with a fake flight for use
in testing.

Signed-off-by: Keith Packard <keithp@keithp.com>
ao-tools/Makefile.am
ao-tools/ao-fakeflight/Makefile.am [new file with mode: 0644]
ao-tools/ao-fakeflight/ao-fake-convert.c [new file with mode: 0644]
ao-tools/ao-fakeflight/ao-fake-log.c [new file with mode: 0644]
ao-tools/ao-fakeflight/ao-fakeflight.c [new file with mode: 0644]
ao-tools/ao-fakeflight/ao-fakeflight.h [new file with mode: 0644]
ao-tools/ao-fakeflight/ao-physics.c [new file with mode: 0644]
ao-tools/ao-fakeflight/ao-rocket.c [new file with mode: 0644]
configure.ac

index fb5548576e0fb1a5be5d9e930294d2a6305a6410..dfb19e1058f19c4ebcd00c8d5448e056c7ef1f00 100644 (file)
@@ -2,7 +2,7 @@ SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list \
        ao-load ao-telem ao-send-telem ao-sky-flash \
        ao-dumpflash ao-edit-telem ao-dump-up ao-elftohex \
        ao-flash ao-usbload ao-test-igniter ao-test-baro \
-       ao-test-flash ao-cal-accel ao-test-gps ao-usbtrng \
+       ao-test-flash ao-cal-accel ao-fakeflight ao-test-gps ao-usbtrng \
        ao-cal-freq ao-chaosread ao-makebin
 if LIBSTLINK
 SUBDIRS += ao-stmload
diff --git a/ao-tools/ao-fakeflight/Makefile.am b/ao-tools/ao-fakeflight/Makefile.am
new file mode 100644 (file)
index 0000000..cf88795
--- /dev/null
@@ -0,0 +1,25 @@
+bin_PROGRAMS=ao-fakeflight
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS) -I$(top_srcdir)/src/drivers -O0 -g
+AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_fakeflight_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
+
+ao_fakeflight_LDADD=$(AO_POSTFLIGHT_LIBS)
+
+LIBS=-lm
+
+ao_fakeflight_SOURCES = \
+       ao-fakeflight.c \
+       ao-fakeflight.h \
+       ao-fake-convert.c \
+       ao-fake-log.c \
+       ao-physics.c \
+       ao-rocket.c
+
+clean-local:
+       $(RM) $(BUILT_SOURCES)
+
+ALTOS=$(top_srcdir)/src
+DRIVERS=$(ALTOS)/drivers
+KERNEL=$(ALTOS)/kernel
diff --git a/ao-tools/ao-fakeflight/ao-fake-convert.c b/ao-tools/ao-fakeflight/ao-fake-convert.c
new file mode 100644 (file)
index 0000000..035d147
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "cc.h"
+#include <ao-fakeflight.h>
+#include <stdio.h>
+#include <math.h>
+
+/* From mega serial 1246 */
+
+struct ao_ms5607_prom  ao_ms5607_prom = {
+       .reserved =  156,
+       .sens =  44229,
+       .off =  38634,
+       .tcs =  27789,
+       .tco =  25015,
+       .tref =  32003,
+       .tempsens =  27647,
+       .crc =  50256,
+};
+
+struct ao_config {
+       int16_t accel_plus_g;
+       int16_t accel_minus_g;
+};
+
+struct ao_config ao_config = {
+       .accel_plus_g = 2028,
+       .accel_minus_g = 2065
+};
+
+#define MIN_VALUE      0
+#define MAX_VALUE      16777216
+#define MID_VALUE      ((MAX_VALUE - MIN_VALUE) / 2)
+
+static void
+ao_ms5607_search (struct ao_ms5607_value       *goal_value,
+                 struct ao_ms5607_sample       *goal_sample,
+                 int   search_temp)
+{
+       struct ao_ms5607_sample sample;
+       struct ao_ms5607_value  value;
+       uint32_t                hi, lo, mid;
+       int32_t                 goal;
+       int32_t                 result;
+
+       if (search_temp) {
+               sample.pres = MID_VALUE;
+               goal = goal_value->temp;
+       } else {
+               sample.temp = goal_sample->temp;
+               goal = goal_value->pres;
+       }
+
+       lo = MIN_VALUE;
+       hi = MAX_VALUE;
+       for (;;) {
+               mid = (hi + lo) >> 1;
+
+               if (mid == lo)
+                       break;
+
+               if (search_temp)
+                       sample.temp = mid;
+               else
+                       sample.pres = mid;
+
+               ao_ms5607_convert(&sample, &value);
+
+               if (search_temp)
+                       result = value.temp;
+               else
+                       result = value.pres;
+
+               if (result == goal)
+                       break;
+
+               if (result < goal)
+                       lo = mid;
+               else
+                       hi = mid;
+       }
+       *goal_sample = sample;
+}
+
+void
+ao_ms5607_unconvert(double altitude,
+                   struct ao_ms5607_sample *ret)
+{
+       double pressure = cc_altitude_to_pressure(altitude);
+       double temperature = cc_altitude_to_temperature(altitude);
+
+       struct ao_ms5607_value  value;
+
+       value.pres = floor (pressure + 0.5);
+       value.temp = floor (temperature * 100 + 0.5);
+
+       /* First back-convert temperature; that's independent of pressure */
+
+       ao_ms5607_search(&value, ret, 1);
+
+       /* Now search for pressure */
+
+       ao_ms5607_search(&value, ret, 0);
+}
+
+int16_t
+ao_accel_unconvert(double accel)
+{
+       int16_t ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g;
+       double  ao_accel_0g = (ao_config.accel_minus_g + ao_config.accel_plus_g) / 2.0;
+       double  ao_accel_scale = GRAVITY * 2.0 / ao_accel_2g;
+
+       int16_t ao_sample_accel = ao_accel_0g - accel/ao_accel_scale;
+
+       return ao_sample_accel;
+}
+
+static void
+ao_ms5607_show(FILE *f, struct rocket *r)
+{
+       fprintf(f, "ms5607 reserved: %u\n", ao_ms5607_prom.reserved);
+       fprintf(f, "ms5607 sens: %u\n", ao_ms5607_prom.sens);
+       fprintf(f, "ms5607 off: %u\n", ao_ms5607_prom.off);
+       fprintf(f, "ms5607 tcs: %u\n", ao_ms5607_prom.tcs);
+       fprintf(f, "ms5607 tco: %u\n", ao_ms5607_prom.tco);
+       fprintf(f, "ms5607 tref: %u\n", ao_ms5607_prom.tref);
+       fprintf(f, "ms5607 tempsens: %u\n", ao_ms5607_prom.tempsens);
+       fprintf(f, "ms5607 crc: %u\n", ao_ms5607_prom.crc);
+}
+
+static void
+ao_config_show(FILE *f, struct rocket *r)
+{
+       fprintf(f, "Config version: 1.18\n");
+       fprintf(f, "Accel cal +1g: %d -1g: %d\n",
+               ao_config.accel_plus_g, ao_config.accel_minus_g);
+       fprintf(f, "Main deploy: %d meters\n", (int) r->main_deploy);
+}
+
+#include "config.h"
+
+void
+ao_show_header(FILE *f, struct rocket *r)
+{
+       ao_config_show(f, r);
+       ao_ms5607_show(f, r);
+       fprintf(f, "serial-number 1\n");
+       fprintf(f, "current-flight 1\n");
+       fprintf(f, "log-format       %u\n", AO_LOG_FORMAT_TELEMETRUM);
+       fprintf(f, "altitude-32      1\n");
+       fprintf(f, "software-version %s\n", PACKAGE_VERSION);
+}
+
+#include "ao_ms5607_convert.c"
diff --git a/ao-tools/ao-fakeflight/ao-fake-log.c b/ao-tools/ao-fakeflight/ao-fake-log.c
new file mode 100644 (file)
index 0000000..4a14bec
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao-fakeflight.h"
+
+static uint8_t
+ao_log_csum(uint8_t *b)
+{
+       uint8_t sum = 0x5a;
+       uint8_t i;
+
+       for (i = 0; i < sizeof (struct ao_log_metrum); i++)
+               sum += *b++;
+       return -sum;
+}
+
+void
+ao_log_metrum(FILE *file, struct ao_log_metrum *log)
+{
+       uint8_t *d;
+
+       /* set checksum */
+       log->csum = 0;
+       log->csum = ao_log_csum((uint8_t *) log);
+       int i;
+
+       fprintf (file, "%c %04x", log->type, log->tick);
+       d = (void *) &log->u;
+       for (i = 0; i < sizeof (log->u); i++)
+               fprintf(file, " %02x", d[i]);
+       fprintf (file, "\n");
+}
+
+void
+ao_log_flight(FILE *file, struct flight *f, struct rocket *r)
+{
+       static struct ao_log_metrum     log;
+
+       log.type = AO_LOG_FLIGHT;
+       log.tick = (f->time * 100);
+       log.u.flight.ground_accel = ao_accel_unconvert(GRAVITY);
+       log.u.flight.ground_pres = cc_altitude_to_pressure(f->altitude);
+       log.u.flight.flight = 1;
+       ao_log_metrum(file, &log);
+}
+
+void
+ao_log_sensor(FILE *file, struct flight *f, struct rocket *r)
+{
+       static struct ao_log_metrum     log;
+       struct ao_ms5607_sample         sample_baro;
+       int16_t                         sample_accel;
+
+       ao_ms5607_unconvert(f->altitude, &sample_baro);
+       sample_accel = ao_accel_unconvert(f->accel);
+
+       log.type = AO_LOG_SENSOR;
+       log.tick = (f->time * 100);
+       log.u.sensor.pres = sample_baro.pres;
+       log.u.sensor.temp = sample_baro.temp;
+       log.u.sensor.accel = sample_accel;
+       ao_log_metrum(file, &log);
+}
+
+void
+ao_log_gps(FILE *file, struct flight *f, struct rocket *r)
+{
+       static struct ao_log_metrum     log;
+       static double                   gps_time;
+       static int                      been_here;
+       int32_t                         altitude;
+       int32_t                         seconds;
+
+       if (been_here && (f->time - gps_time) < 1)
+               return;
+       been_here = 1;
+       gps_time = f->time;
+
+       altitude = f->altitude;
+       seconds = f->time;
+
+       log.type = AO_LOG_GPS_POS;
+       log.tick = (f->time * 100);
+       log.u.gps.latitude = 45 * 1e7;
+       log.u.gps.longitude = -121 * 1e7;
+       log.u.gps.altitude_low = altitude;
+       log.u.gps.altitude_high = altitude >> 16;
+       ao_log_metrum(file, &log);
+
+       log.type = AO_LOG_GPS_TIME;
+       log.tick = (f->time * 100);
+       log.u.gps_time.hour = seconds / 3600;
+       log.u.gps_time.minute = (seconds / 60) % 60;
+       log.u.gps_time.second = seconds % 60;
+       log.u.gps_time.flags = AO_GPS_VALID | AO_GPS_RUNNING | AO_GPS_DATE_VALID | AO_GPS_COURSE_VALID | (12 << AO_GPS_NUM_SAT_SHIFT);
+       log.u.gps_time.year = 114;
+       log.u.gps_time.month = 7;
+       log.u.gps_time.day = 1;
+       log.u.gps_time.pdop = 1;
+
+       ao_log_metrum(file, &log);
+}
+
+void
+ao_log_state(FILE *file, struct flight *f, struct rocket *r)
+{
+       static struct ao_log_metrum     log;
+       static int                      log_state = ao_flight_startup;
+       int                             flight_state;
+
+       switch (f->state) {
+       case state_ascent:
+               if (f->speed == 0 && f->altitude == 0)
+                       flight_state = ao_flight_pad;
+               else if (f->accel > 0)
+                       flight_state = ao_flight_boost;
+               else if (f->speed > 300)
+                       flight_state = ao_flight_fast;
+               else
+                       flight_state = ao_flight_coast;
+               break;
+       case state_drogue:
+               flight_state = ao_flight_drogue;
+               break;
+       case state_main:
+               flight_state = ao_flight_main;
+               break;
+       case state_landed:
+               flight_state = ao_flight_landed;
+               break;
+       }
+       if (flight_state != log_state) {
+               log.type = AO_LOG_STATE;
+               log.tick = (f->time * 100);
+               log.u.state.state = flight_state;
+               log.u.state.reason = 0;
+               ao_log_metrum(file, &log);
+               log_state = flight_state;
+       }
+}
+
+void
+ao_log(FILE *file, struct flight *f, struct rocket *r)
+{
+       static int      been_here = 0;
+
+       if (!been_here) {
+               been_here = 1;
+               ao_log_flight(file, f, r);
+       }
+       ao_log_sensor(file, f, r);
+       ao_log_state(file, f, r);
+       ao_log_gps(file, f, r);
+}
diff --git a/ao-tools/ao-fakeflight/ao-fakeflight.c b/ao-tools/ao-fakeflight/ao-fakeflight.c
new file mode 100644 (file)
index 0000000..8a99259
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao-fakeflight.h"
+
+char *state_name[] = {
+       [state_ascent] = "ascent",
+       [state_drogue] = "drogue",
+       [state_main] = "main",
+       [state_landed] = "landed",
+};
+
+struct rocket o5778 = {
+       .models = {
+               [state_ascent] = {
+                       .cd = 0.5,
+                       .diameter = .100
+               },
+               [state_drogue] = {
+                       .cd = 1.3,
+                       .diameter = .300
+               },
+               [state_main] = {
+                       .cd = 1.3,
+                       .diameter = 1.0
+               },
+       },
+       .empty_mass = 15.0,
+       .main_deploy = 250,
+       .motors = {
+               [0] = {
+                       .fuel_mass = 18.021,
+                       .average_thrust = 5778.0,
+                       .burn_time = 8.52,
+                       .delay = 0.0,
+               },
+               [1] = {
+                       .fuel_mass = 18.021,
+                       .average_thrust = 5778.0,
+                       .burn_time = 0, /* 17.04 */
+                       .delay = 18.0,
+               },
+       },
+};
+
+struct rocket n5778 = {
+       .models = {
+               [state_ascent] = {
+                       .cd = 0.5,
+                       .diameter = .100
+               },
+               [state_drogue] = {
+                       .cd = 1.3,
+                       .diameter = .300
+               },
+               [state_main] = {
+                       .cd = 1.3,
+                       .diameter = 1.0
+               },
+       },
+       .empty_mass = 15.0,
+       .main_deploy = 250,
+       .motors = {
+               [0] = {
+                       .fuel_mass = 9.0105,
+                       .average_thrust = 5778.0,
+                       .burn_time = 4.26,
+                       .delay = 0.0,
+               },
+       },
+};
+
+/*
+ * Move the flight one tick forward
+ */
+void
+step(struct flight *f, struct rocket *r)
+{
+       double  drag = rocket_drag(f, r);
+       double  thrust = rocket_thrust(f, r);
+       double  gravity = rocket_gravity(f, r);
+       double  mass = rocket_mass(f, r);
+       double  accel;
+
+       /* This is our acceleration relative to the earth */
+       accel = (drag + thrust - gravity) / mass;
+
+       /* Because the accelerometer is also affected by gravity, it
+        * only measures *other* forces applied to the rocket
+        */
+       f->accel = (drag + thrust) / mass;
+
+       f->altitude += f->speed * STEP + 0.5 * (accel * STEP) * (accel * STEP);
+       f->speed += accel * STEP;
+       f->time += STEP;
+}
+
+void
+init(struct flight *f, struct rocket *r)
+{
+       double gravity = rocket_gravity(f, r);
+
+       /* The pad is pushing up on the rocket to counter
+        * gravity, so the accelerometer, which only measures
+        * forces other than gravity, sees only this
+        */
+       f->accel = gravity / rocket_mass(f, r);
+       f->speed = 0;
+       f->altitude = 0;
+       f->time += STEP;
+}
+
+void
+fly(FILE *file, struct rocket *r)
+{
+       struct flight f = {
+               .time = -1,
+               .altitude = 0,
+               .speed = 0,
+               .accel = 0,
+               .state = state_ascent,
+       };
+
+       double  max_speed = 0;
+       double  max_alt = 0;
+       double  max_accel = 0;
+
+
+       ao_show_header(file, r);
+       while (f.time < 0) {
+               init(&f, r);
+               ao_log(file, &f, r);
+       }
+       while (f.altitude >= 0) {
+               step(&f, r);
+               switch (f.state) {
+               case state_ascent:
+                       if (f.speed >= 0)
+                               break;
+                       f.state = state_drogue;
+                       /* fall through */
+               case state_drogue:
+                       if (f.altitude > o5778.main_deploy)
+                               break;
+                       f.state = state_main;
+                       /* fall through */
+               case state_main:
+                       break;
+               }
+               ao_log(file, &f, r);
+               max_speed = fmax(max_speed, f.speed);
+               max_accel = fmax(max_accel, f.accel);
+               max_alt = fmax(max_alt, f.altitude);
+       }
+       fprintf(stderr, "max alt %9.1f speed %9.1f accel %9.1f\n",
+               max_alt, max_speed, max_accel);
+}
+
+int
+main(int argc, char **argv)
+{
+       fly(stdout, &o5778);
+//     fly(stdout, &n5778);
+       return 0;
+}
diff --git a/ao-tools/ao-fakeflight/ao-fakeflight.h b/ao-tools/ao-fakeflight/ao-fakeflight.h
new file mode 100644 (file)
index 0000000..fd576a6
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_FAKEFLIGHT_H_
+#define _AO_FAKEFLIGHT_H_
+
+#define __xdata
+#include <stdint.h>
+#include <ao_ms5607.h>
+#include <math.h>
+#include <stdio.h>
+#include "cc.h"
+
+#define GAS_CONSTANT           287.05
+#define STEP                   0.01
+#define GRAVITATIONAL_CONSTANT 6.67384e-11
+#define GRAVITY                        9.807
+#define EARTH_MASS             5.9726e24
+#define EARTH_RADIUS           6375313
+
+enum flight_state {
+       state_ascent,
+       state_drogue,
+       state_main,
+       state_landed,
+       state_num
+};
+
+extern char *state_name[];
+
+struct model {
+       double  cd;
+       double  diameter;
+};
+
+struct motor {
+       double  fuel_mass;
+       double  average_thrust;
+       double  burn_time;
+       double  delay;
+};
+
+#define MAX_MOTORS     12
+
+struct rocket {
+       struct model    models[state_num];
+       double          empty_mass;
+       double          main_deploy;
+       struct motor    motors[MAX_MOTORS];
+};
+
+/* Flight state */
+
+struct flight {
+       double  time;
+       double  altitude;
+       double  speed;
+       double  accel;
+       enum flight_state       state;
+};
+
+/* ao-physics.c */
+
+/* Density of dry air in kg/m³ for a given pressure and temperature. */
+/* Density of dry air in kg/m³ for a given pressure and temperature. */
+double
+density_air(double pressure,           /* Pa */
+           double temperature);        /* °C */
+
+/* Area of a circle */
+double
+area_circle(double diameter);
+
+/* Force due to drag (N) */
+double
+force_drag(double      speed,          /* m/s */
+          double       rho,            /* kg/m³ */
+          double       cd,             /* unitless */
+          double       area);          /* m² */
+
+/* Force due to gravity (N) */
+double
+force_gravity(double   mass,           /* kg */
+             double    altitude);      /* m */
+
+/* ao-rocket.c */
+
+/* Mass (kg) of the airframe */
+double
+rocket_mass(struct flight *f, struct rocket *r);
+
+/* Force (N) due to thrust */
+double
+rocket_thrust(struct flight *f, struct rocket *r);
+
+/* Drag (N) due to air resistance */
+double
+rocket_drag(struct flight *f, struct rocket *r);
+
+/* Force (N) due to gravity */
+double
+rocket_gravity(struct flight *f, struct rocket *r);
+
+/* ao-fake-convert.c */
+void
+ao_ms5607_unconvert(double altitude,
+                   struct ao_ms5607_sample *ret);
+
+int16_t
+ao_accel_unconvert(double accel);
+
+void
+ao_show_header(FILE *f, struct rocket *r);
+
+/* ao-fake-log.c */
+
+void
+ao_log_flight(FILE *file, struct flight *f, struct rocket *r);
+
+void
+ao_log_sensor(FILE *file, struct flight *f, struct rocket *r);
+
+void
+ao_log_state(FILE *file, struct flight *f, struct rocket *r);
+
+#endif
diff --git a/ao-tools/ao-fakeflight/ao-physics.c b/ao-tools/ao-fakeflight/ao-physics.c
new file mode 100644 (file)
index 0000000..114b9e0
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao-fakeflight.h"
+
+/* Density of dry air in kg/m³ for a given pressure and temperature. */
+double
+density_air(double pressure,           /* Pa */
+           double temperature)         /* °C */
+{
+       return pressure / (GAS_CONSTANT * (temperature + 273.15));
+}
+
+/* Area of a circle */
+double
+area_circle(double diameter)
+{
+       double radius = diameter / 2;
+       return M_PI * radius * radius;
+}
+
+/* Force due to drag (N) */
+double
+force_drag(double      speed,          /* m/s */
+          double       rho,            /* kg/m³ */
+          double       cd,             /* unitless */
+          double       area)           /* m² */
+{
+       return 0.5 * rho * (speed * speed) * cd * area;
+}
+
+/* Force due to gravity (N) */
+double
+force_gravity(double   mass,           /* kg */
+             double    altitude)       /* m */
+{
+       double  distance = altitude + EARTH_RADIUS;
+       return GRAVITATIONAL_CONSTANT * EARTH_MASS * mass / (distance * distance);
+}
diff --git a/ao-tools/ao-fakeflight/ao-rocket.c b/ao-tools/ao-fakeflight/ao-rocket.c
new file mode 100644 (file)
index 0000000..18808c6
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao-fakeflight.h"
+
+/* Mass (kg) of the airframe */
+double
+rocket_mass(struct flight *f, struct rocket *r)
+{
+       double  time = f->time;
+       double  m = r->empty_mass;
+       int     n;
+
+       for (n = 0; n < MAX_MOTORS; n++) {
+               struct motor *motor = &r->motors[n];
+               if (motor->burn_time) {
+                       double fuel_time_remain = fmin (motor->burn_time, fmax(motor->burn_time - (time - motor->delay), 0.0));
+                       double fuel_fraction = fuel_time_remain / motor->burn_time;
+                       m += fuel_fraction * motor->fuel_mass;
+               }
+       }
+       return m;
+}
+
+/* Force (N) due to thrust */
+double
+rocket_thrust(struct flight *f, struct rocket *r)
+{
+       double  time = f->time;
+       double  thrust = 0.0;
+       int     n;
+
+       for (n = 0; n < MAX_MOTORS; n++) {
+               struct motor *motor = &r->motors[n];
+               if (motor->burn_time) {
+                       if (motor->delay <= time && time < motor->delay + motor->burn_time)
+                               thrust += motor->average_thrust;
+               }
+       }
+       return thrust;
+}
+
+/* Drag (N) due to air resistance */
+double
+rocket_drag(struct flight *f, struct rocket *r)
+{
+       double  pressure = cc_altitude_to_pressure(f->altitude);
+       double  temperature = cc_altitude_to_temperature(f->altitude);
+       double  drag = force_drag(f->speed, density_air(pressure, temperature),
+                         r->models[f->state].cd,
+                         area_circle(r->models[f->state].diameter));
+
+       /* drag operates in opposition to motion through air */
+       if (f->speed >= 0)
+               drag = -drag;
+
+       return drag;
+}
+
+/* Force (N) due to gravity */
+double
+rocket_gravity(struct flight *f, struct rocket *r)
+{
+       double  gravity = force_gravity(rocket_mass (f, r), f->altitude);
+}
index 9943b92d8ed814e2d8f5f6798979417b3745291c..b4ecfb983c432959fa339d07dadf092e64108200 100644 (file)
@@ -563,6 +563,7 @@ ao-tools/ao-test-gps/Makefile
 ao-tools/ao-usbtrng/Makefile
 ao-tools/ao-chaosread/Makefile
 ao-tools/ao-makebin/Makefile
+ao-tools/ao-fakeflight/Makefile
 ao-utils/Makefile
 src/Version
 ])