all.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
  5. /* Before C99, float variants of math functions are not avaliable. */
  6. static float _sqrtf(float x)
  7. {
  8. return (float)sqrt(x);
  9. }
  10. #define sqrtf _sqrtf
  11. static float _fmodf(float x, float y)
  12. {
  13. return (float)fmod(x, y);
  14. }
  15. #define fmodf _fmodf
  16. /* Before C99, INFINITY may be unavaliable. */
  17. #ifndef INFINITY
  18. #if defined __GNUC__ && (__GNUC__ > 3 || \
  19. (__GNUC__ == 3 && __GNUC_MINOR >= 3))
  20. #define INFINITY (__builtin_inff())
  21. #else
  22. #define INFINITY 1e10000f
  23. #endif
  24. #endif /* INFINITY */
  25. #endif /* __STDC_VERSION__ < 199901L */
  26. static FILE *data_recorder = NULL;
  27. static const char *column_names =
  28. "gx,gy,gz,ax,ay,az,cy,cy_fixed,"
  29. "g,a,g_std,a_std,g_up,a_up,is_out,valley";
  30. struct schmidt
  31. {
  32. float high;
  33. float low;
  34. int value;
  35. };
  36. extern int schmidt_init(struct schmidt *schmidt, float low, float high);
  37. extern int schmidt_trig(struct schmidt *schmidt, float level);
  38. extern int schmidt_get(struct schmidt *schmidt);
  39. #define RINGBUF_MAX_SIZE 100
  40. struct ringbuf
  41. {
  42. float buf[RINGBUF_MAX_SIZE];
  43. float sum;
  44. float sum2;
  45. int cap;
  46. int p;
  47. int full;
  48. };
  49. extern int ringbuf_init(struct ringbuf *ringbuf, int cap);
  50. extern void ringbuf_push(struct ringbuf *ringbuf, float value);
  51. extern int ringbuf_size(struct ringbuf *ringbuf);
  52. extern float ringbuf_mean(struct ringbuf *ringbuf);
  53. extern float ringbuf_variance(struct ringbuf *ringbuf);
  54. extern float ringbuf_stdev(struct ringbuf *ringbuf);
  55. #define MONOTONIC_QUEUE_CAP 80
  56. typedef int (*monotonic_queue_cmp)(float, float);
  57. struct monotonic_queue
  58. {
  59. monotonic_queue_cmp cmp;
  60. float buf[MONOTONIC_QUEUE_CAP];
  61. int h, h_min, t;
  62. int len;
  63. };
  64. extern void monotonic_queue_init(struct monotonic_queue *mq,
  65. monotonic_queue_cmp cmp);
  66. extern int monotonic_queue_push(struct monotonic_queue *mq, float value);
  67. extern int monotonic_queue_pop(struct monotonic_queue *mq);
  68. extern int monotonic_queue_get_min(struct monotonic_queue *mq, float *dest);
  69. extern int monotonic_queue_get_len(struct monotonic_queue *mq);
  70. struct jump_rope_count_config
  71. {
  72. float lg, hg, la, ha, lgz, hgz, a_g_window;
  73. int cy_window, cy_crit, cy_suppress_time, wait_time, dead_zone_time;
  74. int record_valley_time;
  75. };
  76. struct jump_rope_count_device
  77. {
  78. struct schmidt trig_g, trig_a, trig_gz;
  79. struct ringbuf rbuf_g, rbuf_a;
  80. struct monotonic_queue mq_min_cy, mq_max_cy;
  81. int cy_window, cy_crit, cy_suppress_time, wait_time, dead_zone_time;
  82. int record_valley_time;
  83. int cy_suppress, wait_remain_time, dead_zone_remain_time;
  84. int recording_valley;
  85. float last_cy, last_cy_fixed;
  86. float valley;
  87. };
  88. struct sensor_packet
  89. {
  90. float ax, ay, az, gx, gy, gz, cy;
  91. };
  92. enum jump_rope_count_result
  93. {
  94. RESULT_INACTIVE = -1,
  95. RESULT_NONE = 0,
  96. RESULT_TRIGGERED = 1
  97. };
  98. extern int jump_rope_count_device_init(struct jump_rope_count_device *dev,
  99. struct jump_rope_count_config *cfg);
  100. extern int process_packet(struct jump_rope_count_device *dev,
  101. struct sensor_packet *packet,
  102. enum jump_rope_count_result *result);
  103. static int less(float a, float b)
  104. {
  105. return a < b;
  106. }
  107. static int greater(float a, float b)
  108. {
  109. return a > b;
  110. }
  111. int jump_rope_count_device_init(struct jump_rope_count_device *dev,
  112. struct jump_rope_count_config *cfg)
  113. {
  114. int ret;
  115. ret = schmidt_init(&dev->trig_g, cfg->lg, cfg->hg);
  116. if (ret != 0)
  117. return ret;
  118. ret = schmidt_init(&dev->trig_a, cfg->la, cfg->ha);
  119. if (ret != 0)
  120. return ret;
  121. ret = schmidt_init(&dev->trig_gz, cfg->lgz, cfg->hgz);
  122. if (ret != 0)
  123. return ret;
  124. ret = ringbuf_init(&dev->rbuf_a, cfg->a_g_window);
  125. if (ret != 0)
  126. return ret;
  127. ret = ringbuf_init(&dev->rbuf_g, cfg->a_g_window);
  128. if (ret != 0)
  129. return ret;
  130. monotonic_queue_init(&dev->mq_min_cy, less);
  131. monotonic_queue_init(&dev->mq_max_cy, greater);
  132. dev->cy_window = cfg->cy_window;
  133. dev->cy_crit = cfg->cy_crit;
  134. dev->cy_suppress_time = cfg->cy_suppress_time;
  135. dev->wait_time = cfg->wait_time;
  136. dev->dead_zone_time = cfg->dead_zone_time;
  137. dev->cy_suppress = 0;
  138. dev->last_cy = dev->last_cy_fixed = 0;
  139. dev->wait_remain_time = dev->dead_zone_remain_time = 0;
  140. dev->record_valley_time = cfg->record_valley_time;
  141. if (dev->record_valley_time < 0)
  142. dev->record_valley_time = 1;
  143. /* an initial value only used for data recording */
  144. dev->valley = cfg->lgz;
  145. return 0;
  146. }
  147. static float hypot3f(float x, float y, float z)
  148. {
  149. return sqrtf(x*x + y*y + z*z);
  150. }
  151. static float angle_change(float old, float new)
  152. {
  153. float ret = fmodf(new - old, 360.0);
  154. if (ret < -180.0)
  155. ret += 360.0;
  156. if (ret > 180.0)
  157. ret -= 360.0;
  158. return ret;
  159. }
  160. int process_packet(struct jump_rope_count_device *dev,
  161. struct sensor_packet *packet,
  162. enum jump_rope_count_result *result)
  163. {
  164. int ret = 0;
  165. float min, max;
  166. float g = hypot3f(packet->gx, packet->gy, packet->gz);
  167. float a = hypot3f(packet->ax, packet->ay, packet->az);
  168. float gz = packet->gz;
  169. float cy = dev->last_cy_fixed + angle_change(dev->last_cy,
  170. packet->cy);
  171. float std_g, std_a;
  172. dev->last_cy_fixed = cy;
  173. dev->last_cy = packet->cy;
  174. ringbuf_push(&dev->rbuf_g, g);
  175. ringbuf_push(&dev->rbuf_a, a);
  176. std_g = ringbuf_stdev(&dev->rbuf_g);
  177. std_a = ringbuf_stdev(&dev->rbuf_a);
  178. schmidt_trig(&dev->trig_g, std_g);
  179. schmidt_trig(&dev->trig_a, std_a);
  180. ret = monotonic_queue_push(&dev->mq_min_cy, cy);
  181. if (ret != 0)
  182. return ret;
  183. if (monotonic_queue_get_len(&dev->mq_min_cy) > dev->cy_window)
  184. ret = monotonic_queue_pop(&dev->mq_min_cy);
  185. if (ret != 0)
  186. return ret;
  187. ret = monotonic_queue_push(&dev->mq_max_cy, cy);
  188. if (ret != 0)
  189. return ret;
  190. if (monotonic_queue_get_len(&dev->mq_max_cy) > dev->cy_window)
  191. ret = monotonic_queue_pop(&dev->mq_max_cy);
  192. if (ret != 0)
  193. return ret;
  194. if (dev->recording_valley) {
  195. if (--dev->recording_valley == 0)
  196. *result = RESULT_TRIGGERED;
  197. else {
  198. if (dev->valley > gz)
  199. dev->valley = gz;
  200. *result = RESULT_NONE;
  201. }
  202. goto out;
  203. }
  204. ret = monotonic_queue_get_min(&dev->mq_min_cy, &min);
  205. if (ret != 0)
  206. return ret;
  207. ret = monotonic_queue_get_min(&dev->mq_max_cy, &max);
  208. if (ret != 0)
  209. return ret;
  210. if (max - min > dev->cy_crit)
  211. dev->cy_suppress = dev->cy_suppress_time;
  212. if (schmidt_get(&dev->trig_g) == 0 ||
  213. schmidt_get(&dev->trig_a) == 0 ||
  214. dev->cy_suppress > 0)
  215. {
  216. schmidt_trig(&dev->trig_gz, -INFINITY);
  217. *result = RESULT_INACTIVE;
  218. goto out;
  219. }
  220. if (schmidt_trig(&dev->trig_gz, gz) == 1 &&
  221. schmidt_get(&dev->trig_gz) == 0 &&
  222. dev->cy_suppress == 0 &&
  223. dev->dead_zone_remain_time == 0)
  224. {
  225. dev->wait_remain_time = dev->wait_time;
  226. dev->dead_zone_remain_time = dev->dead_zone_time;
  227. dev->recording_valley = dev->record_valley_time;
  228. dev->valley = gz;
  229. *result = RESULT_NONE;
  230. goto out;
  231. }
  232. *result = (dev->wait_remain_time > 0 ? RESULT_NONE :
  233. RESULT_INACTIVE);
  234. out:
  235. if (dev->wait_remain_time)
  236. dev->wait_remain_time--;
  237. if (dev->dead_zone_remain_time)
  238. dev->dead_zone_remain_time--;
  239. if (dev->cy_suppress > 0)
  240. dev->cy_suppress--;
  241. if (data_recorder == NULL)
  242. return 0;
  243. /* column names:
  244. "gx,gy,gz,ax,ay,az,cy,cy_fixed,"
  245. "g,a,g_std,a_std,g_up,a_up,is_out,valley" */
  246. fprintf(data_recorder, "%.7f,%.7f,%.7f,",
  247. packet->gx, packet->gy, packet->gz);
  248. fprintf(data_recorder, "%.7f,%.7f,%.7f,",
  249. packet->ax, packet->ay, packet->az);
  250. fprintf(data_recorder, "%.7f,%.7f,",
  251. dev->last_cy, dev->last_cy_fixed);
  252. fprintf(data_recorder, "%.7f,%.7f,%.7f,%.7f,",
  253. g, a, std_g, std_a);
  254. fprintf(data_recorder, "%d,%d,%d,%.7f\n",
  255. schmidt_get(&dev->trig_g),
  256. schmidt_get(&dev->trig_a),
  257. *result == RESULT_TRIGGERED,
  258. dev->valley);
  259. return 0;
  260. }
  261. void monotonic_queue_init(struct monotonic_queue *mq,
  262. monotonic_queue_cmp cmp)
  263. {
  264. mq->h = mq->h_min = mq->t = mq->len = 0;
  265. mq->cmp = cmp;
  266. }
  267. int monotonic_queue_push(struct monotonic_queue *mq, float value)
  268. {
  269. int t1;
  270. while (mq->h_min != mq->t && mq->cmp(value, mq->buf[mq->h_min]))
  271. mq->h_min = (mq->h_min + 1) % MONOTONIC_QUEUE_CAP;
  272. t1 = (mq->t + 1) % MONOTONIC_QUEUE_CAP;
  273. if (t1 == mq->h)
  274. /* over flow */
  275. return -1;
  276. mq->len++;
  277. mq->buf[mq->t] = value;
  278. mq->t = t1;
  279. return 0;
  280. }
  281. int monotonic_queue_pop(struct monotonic_queue *mq)
  282. {
  283. if (mq->h == mq->t)
  284. /* empty */
  285. return -1;
  286. mq->len--;
  287. if (mq->h == mq->h_min)
  288. mq->h_min = (mq->h_min + 1) % MONOTONIC_QUEUE_CAP;
  289. mq->h = (mq->h + 1) % MONOTONIC_QUEUE_CAP;
  290. return 0;
  291. }
  292. int monotonic_queue_get_min(struct monotonic_queue *mq, float *dest)
  293. {
  294. if (mq->h == mq->t)
  295. /* empty */
  296. return -1;
  297. *dest = mq->buf[mq->h_min];
  298. return 0;
  299. }
  300. int monotonic_queue_get_len(struct monotonic_queue *mq)
  301. {
  302. return mq->len;
  303. }
  304. int ringbuf_init(struct ringbuf *ringbuf, int cap)
  305. {
  306. if (cap > RINGBUF_MAX_SIZE)
  307. return -1;
  308. ringbuf->p = 0;
  309. ringbuf->full = 0;
  310. ringbuf->sum = ringbuf->sum2 = 0.0;
  311. ringbuf->cap = cap;
  312. return 0;
  313. }
  314. void ringbuf_push(struct ringbuf *ringbuf, float value)
  315. {
  316. if (ringbuf->full) {
  317. float old = ringbuf->buf[ringbuf->p];
  318. ringbuf->sum -= old;
  319. ringbuf->sum2 -= old * old;
  320. }
  321. ringbuf->sum += value;
  322. ringbuf->sum2 += value * value;
  323. ringbuf->buf[ringbuf->p++] = value;
  324. if (ringbuf->p == ringbuf->cap) {
  325. ringbuf->p = 0;
  326. ringbuf->full = 1;
  327. }
  328. }
  329. int ringbuf_size(struct ringbuf *ringbuf)
  330. {
  331. return ringbuf->full ? ringbuf->cap : ringbuf->p;
  332. }
  333. float ringbuf_mean(struct ringbuf *ringbuf)
  334. {
  335. int sz = ringbuf_size(ringbuf);
  336. if (sz == 0)
  337. return 0;
  338. return ringbuf->sum / sz;
  339. }
  340. float ringbuf_variance(struct ringbuf *ringbuf)
  341. {
  342. float mean;
  343. int sz = ringbuf_size(ringbuf);
  344. if (sz == 0)
  345. return 0;
  346. mean = ringbuf_mean(ringbuf);
  347. return ringbuf->sum2 / sz - mean * mean;
  348. }
  349. float ringbuf_stdev(struct ringbuf *ringbuf)
  350. {
  351. return sqrt(ringbuf_variance(ringbuf));
  352. }
  353. int schmidt_init(struct schmidt *schmidt, float low, float high)
  354. {
  355. if (low > high)
  356. return -1;
  357. schmidt->high = high;
  358. schmidt->low = low;
  359. schmidt->value = 0;
  360. return 0;
  361. }
  362. int schmidt_trig(struct schmidt *schmidt, float level)
  363. {
  364. if ((schmidt->value == 1 && level <= schmidt->low) ||
  365. (schmidt->value == 0 && level >= schmidt->high)) {
  366. schmidt->value ^= 1;
  367. return 1;
  368. }
  369. return 0;
  370. }
  371. int schmidt_get(struct schmidt *schmidt)
  372. {
  373. return schmidt->value;
  374. }
  375. const int fs = 50;
  376. int main()
  377. {
  378. struct jump_rope_count_config cfg;
  379. struct jump_rope_count_device dev;
  380. struct sensor_packet packet;
  381. int count = 0, ret;
  382. enum jump_rope_count_result result;
  383. data_recorder = fopen("data_record.csv", "w");
  384. if (data_recorder == NULL)
  385. fprintf(stderr, "can not open data_record.csv\n");
  386. else
  387. fprintf(data_recorder, "%s\n", column_names);
  388. cfg.lg = 0.5;
  389. cfg.hg = 1.5;
  390. cfg.la = 4.0;
  391. cfg.ha = 6.0;
  392. cfg.lgz = -1.5;
  393. cfg.hgz = 2;
  394. cfg.a_g_window = 100;
  395. cfg.cy_window = fs * 0.1;
  396. cfg.cy_crit = 200;
  397. cfg.cy_suppress_time = fs * 0.2;
  398. cfg.wait_time = fs * 1;
  399. cfg.dead_zone_time = fs * 0.2;
  400. cfg.record_valley_time = fs * 0.1;
  401. if (jump_rope_count_device_init(&dev, &cfg) != 0)
  402. abort();
  403. while (scanf("%f%f%f%f%f%f%f",
  404. &packet.gx, &packet.gy, &packet.gz,
  405. &packet.ax, &packet.ay, &packet.az,
  406. &packet.cy) == 7) {
  407. ret = process_packet(&dev, &packet, &result);
  408. if (ret != 0)
  409. abort();
  410. if (result == RESULT_INACTIVE) {
  411. if (count > 1)
  412. printf("%d\n", count - 1);
  413. count = 0;
  414. } else if (result == RESULT_TRIGGERED)
  415. count += 1;
  416. }
  417. if (count > 1)
  418. printf("%d\n", count - 1);
  419. return 0;
  420. }
  421. /* vim: set ts=8 sw=8 sts=8 noet: */