123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
- /* Before C99, float variants of math functions are not avaliable. */
- static float _sqrtf(float x)
- {
- return (float)sqrt(x);
- }
- #define sqrtf _sqrtf
- static float _fmodf(float x, float y)
- {
- return (float)fmod(x, y);
- }
- #define fmodf _fmodf
- /* Before C99, INFINITY may be unavaliable. */
- #ifndef INFINITY
- #if defined __GNUC__ && (__GNUC__ > 3 || \
- (__GNUC__ == 3 && __GNUC_MINOR >= 3))
- #define INFINITY (__builtin_inff())
- #else
- #define INFINITY 1e10000f
- #endif
- #endif /* INFINITY */
- #endif /* __STDC_VERSION__ < 199901L */
- static FILE *data_recorder = NULL;
- static const char *column_names =
- "gx,gy,gz,ax,ay,az,cy,cy_fixed,"
- "g,a,g_std,a_std,g_up,a_up,is_out";
- struct schmidt
- {
- float high;
- float low;
- int value;
- };
- extern int schmidt_init(struct schmidt *schmidt, float low, float high);
- extern int schmidt_trig(struct schmidt *schmidt, float level);
- extern int schmidt_get(struct schmidt *schmidt);
- #define RINGBUF_MAX_SIZE 100
- struct ringbuf
- {
- float buf[RINGBUF_MAX_SIZE];
- float sum;
- float sum2;
- int cap;
- int p;
- int full;
- };
- extern int ringbuf_init(struct ringbuf *ringbuf, int cap);
- extern void ringbuf_push(struct ringbuf *ringbuf, float value);
- extern int ringbuf_size(struct ringbuf *ringbuf);
- extern float ringbuf_mean(struct ringbuf *ringbuf);
- extern float ringbuf_variance(struct ringbuf *ringbuf);
- extern float ringbuf_stdev(struct ringbuf *ringbuf);
- #define MONOTONIC_QUEUE_CAP 80
- typedef int (*monotonic_queue_cmp)(float, float);
- struct monotonic_queue
- {
- monotonic_queue_cmp cmp;
- float buf[MONOTONIC_QUEUE_CAP];
- int h, h_min, t;
- int len;
- };
- extern void monotonic_queue_init(struct monotonic_queue *mq,
- monotonic_queue_cmp cmp);
- extern int monotonic_queue_push(struct monotonic_queue *mq, float value);
- extern int monotonic_queue_pop(struct monotonic_queue *mq);
- extern int monotonic_queue_get_min(struct monotonic_queue *mq, float *dest);
- extern int monotonic_queue_get_len(struct monotonic_queue *mq);
- struct jump_rope_count_config
- {
- float lg, hg, la, ha, lgz, hgz, a_g_window;
- int cy_window, cy_crit, cy_suppress_time, wait_time, dead_zone_time;
- };
- struct jump_rope_count_device
- {
- struct schmidt trig_g, trig_a, trig_gz;
- struct ringbuf rbuf_g, rbuf_a;
- struct monotonic_queue mq_min_cy, mq_max_cy;
- int cy_window, cy_crit, cy_suppress_time, wait_time, dead_zone_time;
- int cy_suppress, wait_remain_time, dead_zone_remain_time;
- float last_cy, last_cy_fixed;
- };
- struct sensor_packet
- {
- float ax, ay, az, gx, gy, gz, cy;
- };
- enum jump_rope_count_result
- {
- RESULT_INACTIVE = -1,
- RESULT_NONE = 0,
- RESULT_TRIGGERED = 1
- };
- extern int jump_rope_count_device_init(struct jump_rope_count_device *dev,
- struct jump_rope_count_config *cfg);
- extern int process_packet(struct jump_rope_count_device *dev,
- struct sensor_packet *packet,
- enum jump_rope_count_result *result);
- static int less(float a, float b)
- {
- return a < b;
- }
- static int greater(float a, float b)
- {
- return a > b;
- }
- int jump_rope_count_device_init(struct jump_rope_count_device *dev,
- struct jump_rope_count_config *cfg)
- {
- int ret;
- ret = schmidt_init(&dev->trig_g, cfg->lg, cfg->hg);
- if (ret != 0)
- return ret;
- ret = schmidt_init(&dev->trig_a, cfg->la, cfg->ha);
- if (ret != 0)
- return ret;
- ret = schmidt_init(&dev->trig_gz, cfg->lgz, cfg->hgz);
- if (ret != 0)
- return ret;
- ret = ringbuf_init(&dev->rbuf_a, cfg->a_g_window);
- if (ret != 0)
- return ret;
- ret = ringbuf_init(&dev->rbuf_g, cfg->a_g_window);
- if (ret != 0)
- return ret;
- monotonic_queue_init(&dev->mq_min_cy, less);
- monotonic_queue_init(&dev->mq_max_cy, greater);
- dev->cy_window = cfg->cy_window;
- dev->cy_crit = cfg->cy_crit;
- dev->cy_suppress_time = cfg->cy_suppress_time;
- dev->wait_time = cfg->wait_time;
- dev->dead_zone_time = cfg->dead_zone_time;
- dev->cy_suppress = 0;
- dev->last_cy = dev->last_cy_fixed = 0;
- dev->wait_remain_time = dev->dead_zone_remain_time = 0;
- return 0;
- }
- static float hypot3f(float x, float y, float z)
- {
- return sqrtf(x*x + y*y + z*z);
- }
- static float angle_change(float old, float new)
- {
- float ret = fmodf(new - old, 360.0);
- if (ret < -180.0)
- ret += 360.0;
- if (ret > 180.0)
- ret -= 360.0;
- return ret;
- }
- int process_packet(struct jump_rope_count_device *dev,
- struct sensor_packet *packet,
- enum jump_rope_count_result *result)
- {
- int ret = 0;
- float min, max;
- float g = hypot3f(packet->gx, packet->gy, packet->gz);
- float a = hypot3f(packet->ax, packet->ay, packet->az);
- float gz = packet->gz;
- float cy = dev->last_cy_fixed + angle_change(dev->last_cy,
- packet->cy);
- float std_g, std_a;
- dev->last_cy_fixed = cy;
- dev->last_cy = packet->cy;
- ringbuf_push(&dev->rbuf_g, g);
- ringbuf_push(&dev->rbuf_a, a);
- std_g = ringbuf_stdev(&dev->rbuf_g);
- std_a = ringbuf_stdev(&dev->rbuf_a);
- schmidt_trig(&dev->trig_g, std_g);
- schmidt_trig(&dev->trig_a, std_a);
- ret = monotonic_queue_push(&dev->mq_min_cy, cy);
- if (ret != 0)
- return ret;
- if (monotonic_queue_get_len(&dev->mq_min_cy) > dev->cy_window)
- ret = monotonic_queue_pop(&dev->mq_min_cy);
- if (ret != 0)
- return ret;
- ret = monotonic_queue_push(&dev->mq_max_cy, cy);
- if (ret != 0)
- return ret;
- if (monotonic_queue_get_len(&dev->mq_max_cy) > dev->cy_window)
- ret = monotonic_queue_pop(&dev->mq_max_cy);
- if (ret != 0)
- return ret;
- ret = monotonic_queue_get_min(&dev->mq_min_cy, &min);
- if (ret != 0)
- return ret;
- ret = monotonic_queue_get_min(&dev->mq_max_cy, &max);
- if (ret != 0)
- return ret;
- if (max - min > dev->cy_crit)
- dev->cy_suppress = dev->cy_suppress_time;
- if (schmidt_get(&dev->trig_g) == 0 ||
- schmidt_get(&dev->trig_a) == 0 ||
- dev->cy_suppress > 0)
- {
- schmidt_trig(&dev->trig_gz, -INFINITY);
- *result = RESULT_INACTIVE;
- goto out;
- }
- if (schmidt_trig(&dev->trig_gz, gz) == 1 &&
- schmidt_get(&dev->trig_gz) == 0 &&
- dev->cy_suppress == 0 &&
- dev->dead_zone_remain_time == 0)
- {
- dev->wait_remain_time = dev->wait_time;
- dev->dead_zone_remain_time = dev->dead_zone_time;
- *result = RESULT_TRIGGERED;
- goto out;
- }
- if (dev->wait_remain_time)
- dev->wait_remain_time--;
- if (dev->dead_zone_remain_time)
- dev->dead_zone_remain_time--;
- *result = (dev->wait_remain_time > 0 ? RESULT_NONE :
- RESULT_INACTIVE);
- out:
- if (dev->cy_suppress > 0)
- dev->cy_suppress--;
- if (data_recorder == NULL)
- return 0;
- /* column names:
- "gx,gy,gz,ax,ay,az,cy,cy_fixed,"
- "g,a,g_std,a_std,g_up,a_up,is_out" */
- fprintf(data_recorder, "%.7f,%.7f,%.7f,",
- packet->gx, packet->gy, packet->gz);
- fprintf(data_recorder, "%.7f,%.7f,%.7f,",
- packet->ax, packet->ay, packet->az);
- fprintf(data_recorder, "%.7f,%.7f,",
- dev->last_cy, dev->last_cy_fixed);
- fprintf(data_recorder, "%.7f,%.7f,%.7f,%.7f,",
- g, a, std_g, std_a);
- fprintf(data_recorder, "%d,%d,%d\n",
- schmidt_get(&dev->trig_g),
- schmidt_get(&dev->trig_a),
- *result == RESULT_TRIGGERED);
- return 0;
- }
- void monotonic_queue_init(struct monotonic_queue *mq,
- monotonic_queue_cmp cmp)
- {
- mq->h = mq->h_min = mq->t = mq->len = 0;
- mq->cmp = cmp;
- }
- int monotonic_queue_push(struct monotonic_queue *mq, float value)
- {
- int t1;
- while (mq->h_min != mq->t && mq->cmp(value, mq->buf[mq->h_min]))
- mq->h_min = (mq->h_min + 1) % MONOTONIC_QUEUE_CAP;
- t1 = (mq->t + 1) % MONOTONIC_QUEUE_CAP;
- if (t1 == mq->h)
- /* over flow */
- return -1;
- mq->len++;
- mq->buf[mq->t] = value;
- mq->t = t1;
- return 0;
- }
- int monotonic_queue_pop(struct monotonic_queue *mq)
- {
- if (mq->h == mq->t)
- /* empty */
- return -1;
- mq->len--;
- if (mq->h == mq->h_min)
- mq->h_min = (mq->h_min + 1) % MONOTONIC_QUEUE_CAP;
- mq->h = (mq->h + 1) % MONOTONIC_QUEUE_CAP;
- return 0;
- }
- int monotonic_queue_get_min(struct monotonic_queue *mq, float *dest)
- {
- if (mq->h == mq->t)
- /* empty */
- return -1;
- *dest = mq->buf[mq->h_min];
- return 0;
- }
- int monotonic_queue_get_len(struct monotonic_queue *mq)
- {
- return mq->len;
- }
- int ringbuf_init(struct ringbuf *ringbuf, int cap)
- {
- if (cap > RINGBUF_MAX_SIZE)
- return -1;
- ringbuf->p = 0;
- ringbuf->full = 0;
- ringbuf->sum = ringbuf->sum2 = 0.0;
- ringbuf->cap = cap;
- return 0;
- }
- void ringbuf_push(struct ringbuf *ringbuf, float value)
- {
- if (ringbuf->full) {
- float old = ringbuf->buf[ringbuf->p];
- ringbuf->sum -= old;
- ringbuf->sum2 -= old * old;
- }
- ringbuf->sum += value;
- ringbuf->sum2 += value * value;
- ringbuf->buf[ringbuf->p++] = value;
- if (ringbuf->p == ringbuf->cap) {
- ringbuf->p = 0;
- ringbuf->full = 1;
- }
- }
- int ringbuf_size(struct ringbuf *ringbuf)
- {
- return ringbuf->full ? ringbuf->cap : ringbuf->p;
- }
- float ringbuf_mean(struct ringbuf *ringbuf)
- {
- int sz = ringbuf_size(ringbuf);
- if (sz == 0)
- return 0;
- return ringbuf->sum / sz;
- }
- float ringbuf_variance(struct ringbuf *ringbuf)
- {
- float mean;
- int sz = ringbuf_size(ringbuf);
- if (sz == 0)
- return 0;
- mean = ringbuf_mean(ringbuf);
- return ringbuf->sum2 / sz - mean * mean;
- }
- float ringbuf_stdev(struct ringbuf *ringbuf)
- {
- return sqrt(ringbuf_variance(ringbuf));
- }
- int schmidt_init(struct schmidt *schmidt, float low, float high)
- {
- if (low > high)
- return -1;
- schmidt->high = high;
- schmidt->low = low;
- schmidt->value = 0;
- return 0;
- }
- int schmidt_trig(struct schmidt *schmidt, float level)
- {
- if ((schmidt->value == 1 && level <= schmidt->low) ||
- (schmidt->value == 0 && level >= schmidt->high)) {
- schmidt->value ^= 1;
- return 1;
- }
- return 0;
- }
- int schmidt_get(struct schmidt *schmidt)
- {
- return schmidt->value;
- }
- const int fs = 50;
- int main()
- {
- struct jump_rope_count_config cfg;
- struct jump_rope_count_device dev;
- struct sensor_packet packet;
- int count = 0, ret;
- enum jump_rope_count_result result;
- data_recorder = fopen("data_record.csv", "w");
- if (data_recorder == NULL)
- fprintf(stderr, "can not open data_record.csv\n");
- else
- fprintf(data_recorder, "%s\n", column_names);
- cfg.lg = 0.5;
- cfg.hg = 1.5;
- cfg.la = 4.0;
- cfg.ha = 6.0;
- cfg.lgz = -1.5;
- cfg.hgz = 2;
- cfg.a_g_window = 100;
- cfg.cy_window = fs * 0.1;
- cfg.cy_crit = 200;
- cfg.cy_suppress_time = fs * 0.2;
- cfg.wait_time = fs * 1;
- cfg.dead_zone_time = fs * 0.2;
- if (jump_rope_count_device_init(&dev, &cfg) != 0)
- abort();
- while (scanf("%f%f%f%f%f%f%f",
- &packet.gx, &packet.gy, &packet.gz,
- &packet.ax, &packet.ay, &packet.az,
- &packet.cy) == 7) {
- ret = process_packet(&dev, &packet, &result);
- if (ret != 0)
- abort();
- if (result == RESULT_INACTIVE) {
- if (count > 1)
- printf("%d\n", count - 1);
- count = 0;
- } else if (result == RESULT_TRIGGERED)
- count += 1;
- }
- if (count > 1)
- printf("%d\n", count - 1);
- return 0;
- }
- /* vim: set ts=8 sw=8 sts=8 noet: */
|