mirror of
https://github.com/google/pebble.git
synced 2025-07-28 02:04:53 -04:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
10
third_party/Kraepelin/LICENSE
vendored
Normal file
10
third_party/Kraepelin/LICENSE
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Nathaniel T. Stockham
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
2122
third_party/Kraepelin/kraepelin_algorithm/kraepelin_algorithm.c
vendored
Normal file
2122
third_party/Kraepelin/kraepelin_algorithm/kraepelin_algorithm.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
151
third_party/Kraepelin/kraepelin_algorithm/kraepelin_algorithm.h
vendored
Normal file
151
third_party/Kraepelin/kraepelin_algorithm/kraepelin_algorithm.h
vendored
Normal file
|
@ -0,0 +1,151 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "applib/accel_service.h"
|
||||
#include "util/time/time.h"
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Equates
|
||||
// number of samples per second
|
||||
#define KALG_SAMPLE_HZ 25
|
||||
|
||||
// Number of grams per kilogram
|
||||
#define KALG_GRAMS_PER_KG 1000
|
||||
|
||||
typedef struct KAlgState KAlgState;
|
||||
|
||||
// This value in the encoded_vmc field of a KalgSleepMinute structure indicates that the
|
||||
// watch was not worn
|
||||
#define KALG_ENCODED_VMC_NOT_WORN 0
|
||||
|
||||
// The minimum value if the watch was worn
|
||||
#define KALG_ENCODED_VMC_MIN_WORN_VALUE 1
|
||||
|
||||
// The maximum amount of time it takes for the sleep algorithm to figure out that the user
|
||||
// woke up. This is used by activity_algorithm_kraepelin.c at compile time so it must be
|
||||
// hard-coded. The correct value is checked in kalg_init() using a PBL_ASSERT since it can't
|
||||
// be checked at compile time.
|
||||
// should be: KALG_SLEEP_PARAMS.max_wake_minutes_early + KALG_SLEEP_HALF_WIDTH + 1
|
||||
#define KALG_MAX_UNCERTAIN_SLEEP_M 19
|
||||
|
||||
// Activity types, used in KAlgSleepSessionCallback callback
|
||||
typedef enum {
|
||||
// ActivityType_Sleep encapsulates an entire sleep session from sleep entry to wake, and
|
||||
// contains both light and deep sleep periods. An ActivityType_RestfulSleep session identifies
|
||||
// a restful period and its start and end times will always be inside of a ActivityType_Sleep
|
||||
// session.
|
||||
KAlgActivityType_Sleep,
|
||||
|
||||
// A restful period, these will always be inside of a ActivityType_Sleep session
|
||||
KAlgActivityType_RestfulSleep,
|
||||
|
||||
// A "sigificant" length walk
|
||||
KAlgActivityType_Walk,
|
||||
|
||||
// A run
|
||||
KAlgActivityType_Run,
|
||||
|
||||
// Leave at end
|
||||
KAlgActivityTypeCount,
|
||||
} KAlgActivityType;
|
||||
|
||||
// Sleep stats, returned by kalg_get_sleep_stats
|
||||
typedef struct {
|
||||
time_t sleep_start_utc; // start time of a recent sleep session. 0 if no session recently
|
||||
// detected, where "recent" means within the last
|
||||
// minimum_sleep_session_length minutes (currently 60).
|
||||
uint16_t sleep_len_m; // how many minutes of that sleep are *certain*, 0 if none.
|
||||
time_t uncertain_start_utc; // start time of the uncertain area of the sleep session, which
|
||||
// always continues until the present time, 0 if none.
|
||||
} KAlgOngoingSleepStats;
|
||||
|
||||
// Callback called by kalg_activities_update to register activity sessions.
|
||||
// @param[in] context the context passed to kalg_activities_update()
|
||||
// @param[in] activity_type the type of activity
|
||||
// @param[in] start_utc start time of the activity
|
||||
// @param[in] len_sec length of the activity
|
||||
// @param[in] ongoing true if the activity is still ongoing, false if it ended
|
||||
// @param[in] delete if true, delete this session that was previously added
|
||||
// @param[in] steps the number of steps taken in this activity
|
||||
// @param[in] resting_calories the number of resting calories burned
|
||||
// @param[in] active_calories the number of active calories burned
|
||||
// @param[in] distance_mm the distance covered, in millimeters
|
||||
typedef void (*KAlgActivitySessionCallback)(void *context, KAlgActivityType activity_type,
|
||||
time_t start_utc, uint32_t len_sec, bool ongoing,
|
||||
bool delete, uint32_t steps, uint32_t resting_calories,
|
||||
uint32_t active_calories, uint32_t distance_mm);
|
||||
|
||||
// Callback called by kalg_analyze_samples and kalg_compute_activities to record
|
||||
// statistics. This is used during algorithm development, not during normal runtime. The algorithm
|
||||
// passes a list of statistic names and their values to this callback so that they can be
|
||||
// collected and summarized
|
||||
// @param[in] num_stats the number of elements in the names and stats arrays
|
||||
// @param[in] names list of statistic names
|
||||
// @param[in] stats the value for each statistic
|
||||
typedef void (*KAlgStatsCallback)(uint32_t num_stats, const char **names, int32_t *stats);
|
||||
|
||||
// Return the amount of space needed for the state
|
||||
uint32_t kalg_state_size(void);
|
||||
|
||||
// Init the state, return true on success
|
||||
// @param[in] stats_cb if not NULL, this callback will be called while analyzing samples with
|
||||
// statistics that are computed.
|
||||
bool kalg_init(KAlgState *state, KAlgStatsCallback stats_cb);
|
||||
|
||||
// Analyze a set of accel samples
|
||||
// @param[in] state the state structure passed into kalg_init
|
||||
// @param[in] samples array of accel samples
|
||||
// @param[in] num_samples number of samples in the samples array
|
||||
// @param[out] consumed_samples The number of samples that were just consumed to compute steps
|
||||
// For many algorithms, this will often be 0 because the algorithm will wait until
|
||||
// it has stored up a larger batch before it runs the step algorithm on the samples.
|
||||
// @return number of steps counted
|
||||
uint32_t kalg_analyze_samples(KAlgState *state, AccelRawData *samples, uint32_t num_samples,
|
||||
uint32_t *consumed_samples);
|
||||
|
||||
// Return the last minute's stats and reset them for the next minute. The minute stats are logged
|
||||
// and also used for computing sleep
|
||||
// @param[in] state the state structure passed into kalg_init
|
||||
// @param[out] vmc the vmc (Vector Magnitude Counts) value is returned here
|
||||
// @param[out] orientation the orientation value is returned here
|
||||
// @param[out] still true if no movement above noise threshold was detected
|
||||
void kalg_minute_stats(KAlgState *state, uint16_t *vmc, uint8_t *orientation, bool *still);
|
||||
|
||||
// Used by unit tests - run the partial epoch that hasn't been processed yet by
|
||||
// kalg_analyze_samples()
|
||||
// @param[in] state the state structure passed into kalg_init
|
||||
// @return number of steps counted
|
||||
uint32_t kalg_analyze_finish_epoch(KAlgState *state);
|
||||
|
||||
// Feed new minute data into the activity detection state machine. This logic looks for non-sleep
|
||||
// activities, like walks, runs, etc.
|
||||
// @param[in] state the state structure passed into kalg_init
|
||||
// @param[in] utc_now current timestamp in UTC
|
||||
// @param[in] steps number of steps taken in the last minute
|
||||
// @param[in] vmc VMC for the last minute
|
||||
// @param[in] orientation average orientation for the last minute
|
||||
// @param[in] plugged_in true if watch is plugged into charger
|
||||
// @param[in] resting_calories number of resting calories burned in the last minute
|
||||
// @param[in] active_calories number of active calories burned in the last minute
|
||||
// @param[in] distance_mm distance covered in millimeters in the last minute
|
||||
// @param[in] sessions_cb this callback will be called by kalg_compute_activities() for every
|
||||
// session that it finds.
|
||||
// @param[in] context passed to the sessions_cb
|
||||
void kalg_activities_update(KAlgState *state, time_t utc_now, uint16_t steps, uint16_t vmc,
|
||||
uint8_t orientation, bool plugged_in, uint32_t resting_calories,
|
||||
uint32_t active_calories, uint32_t distance_mm, bool shutting_down,
|
||||
KAlgActivitySessionCallback sessions_cb, void *context);
|
||||
|
||||
// Return the timestamp of the last minute that was processed for the given activity type
|
||||
// @param[in] state the state structure passed into kalg_init
|
||||
// @param[in] activity which type of activity
|
||||
time_t kalg_activity_last_processed_time(KAlgState *state, KAlgActivityType activity);
|
||||
|
||||
// Get sleep stats
|
||||
// @param[out] stats this structure is filled in with the sleep stats
|
||||
void kalg_get_sleep_stats(KAlgState *state, KAlgOngoingSleepStats *stats);
|
||||
|
||||
//! Tells the algorithm whether or not it should automatically track activities
|
||||
//! @param enable true to start tracking, false to stop tracking
|
||||
void kalg_enable_activity_tracking(KAlgState *kalg_state, bool enable);
|
563
third_party/Kraepelin/kraepelin_reference/ProjectK_worker.c
vendored
Normal file
563
third_party/Kraepelin/kraepelin_reference/ProjectK_worker.c
vendored
Normal file
|
@ -0,0 +1,563 @@
|
|||
/* Project Kraepelin, Main file
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015, Nathaniel T. Stockham
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
This license is taken to apply to any other files in the Project Kraepelin
|
||||
Pebble App roject.
|
||||
*/
|
||||
|
||||
|
||||
#include "ProjectK_worker.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/* META DATA CODES */
|
||||
|
||||
/* BEHAVIOR CONSTANTS */
|
||||
static const int16_t SMP_HZ = 25; // number of samples taken per second
|
||||
static const int16_t N_SMP_EPOCH = (5*25); // 5*25 = 125 samples recorded, 5 seconds for step count
|
||||
static const int16_t FFT_PWR_TWO = 7; // 2^7 = 128 elements > 125 to allow fft
|
||||
static const int16_t SIZE_EPOCH = 128; // 2^7 = 128 points, zero padding by 13 samples
|
||||
static const int16_t SIZE_BLK_HEAD = 16; // # of bytes in head, all non-acti data including timemood
|
||||
static const int16_t SIZE_BLK_TIME = 4; // # of bytes for storing timestamp
|
||||
static const int16_t SIZE_SUMM = 2; // number of bytes in individual summary
|
||||
static const int16_t N_BLK_PERSIST = 12; // 12 < 14, # blocks, ie: # key-value pairs in persist storage
|
||||
static const int16_t N_SUMM_BLK = 120; // 120, number of summaries in a appmessage block
|
||||
// ^-->NEEDS TO BE DIVISABLE by N_STEPC_BLK
|
||||
|
||||
static const int16_t N_STEPC_BLK = 10; // 4 number of step count recording per block
|
||||
static const int16_t N_MIN_VMC_0_NONWEAR = 60; // 4 number of step count recording per block
|
||||
|
||||
|
||||
/* METRIC MANIPULATION */
|
||||
static const int16_t LVL_SCL = 8; // the number of milligs between discrete levels
|
||||
static const int16_t LVL_SHIFT = 3; // 2^LVL_SHIFT = LVL_SCL
|
||||
static const uint8_t N_ANG = 16; // for orient_encode, # of angles possible chosen
|
||||
/* FFT_SCL reduces the data size so doesnt overflow on the transforms. Divide by 4 to
|
||||
* get max at 125, and divide by 2 to get fourier DC to max at 512*125/2 = 32000 < 32768 the
|
||||
* overflow boundry for 16 bit *signed* ints */
|
||||
static const int16_t FFT_SCL = 2; // 125*500/2 = 25000 prevent overflow on the transforms, assuming +-250
|
||||
static const int16_t MAX_VM = 1000; // make smaller to prevent overflow on the FFT
|
||||
static const uint32_t VMCPM_SCL = 10; // scaled needed to prevent overflow in adding
|
||||
static const uint32_t PIM_LVL_THRES = 5; /* mean # levels thres PIM, 2 lvl -> 5*0.008G = 0.056G
|
||||
* we do this to match the actigraph, and this seems to be the *minimum* level (==3)that rejects
|
||||
* noise when the pebble is perfectly still */
|
||||
|
||||
/* METRIC STORAGE SCALING*/
|
||||
static const uint32_t STEPC_SCL = 25; // step resolution, scale count to stuff into uint8_t
|
||||
|
||||
/* AXIS AND ORIENTATION VARIABLES */
|
||||
static const int16_t N_AXIS = 3;
|
||||
|
||||
/* BEHAVIOUR CONSTS */
|
||||
// REMEMEBER, CURRENTLY THIS IS ONLY CHECKED ONCE PER EACH BLOCK, SO IT WANT
|
||||
// CHECKED MORE OFTEN THEN MUST PUT IN MINUTE HANDLER!!
|
||||
static const uint16_t SUMM_BTWN_TRANSMIT_SERVER = 120; // 300 = 5 hours
|
||||
static const uint16_t SUMM_BTWN_WEAR_REMINDER = 60; // 60 = 1 hours
|
||||
|
||||
|
||||
/* ARRAY POINTERS : storage and work arrays */
|
||||
static int16_t *pt_ary[3];
|
||||
static int16_t *work_ary;
|
||||
static uint8_t *blk_buf;
|
||||
|
||||
/* STATE VARIABLES */
|
||||
static uint16_t i_smp = 0; // the index of the sample, relative to the epoch
|
||||
|
||||
/* SUMMARY METRICS */
|
||||
static int16_t mean_ary[3];
|
||||
static uint32_t pim_ary[3];
|
||||
static uint32_t stepc;
|
||||
static uint32_t x1000_kcal_blk;
|
||||
static uint32_t stepc_prev_5sec = 0;
|
||||
static uint32_t stepc_prev_10sec = 0;
|
||||
// static uint32_t stepc_daily;
|
||||
|
||||
|
||||
/* BEHAVIOUR VARIABLES */
|
||||
static uint16_t summ_since_trans_server = 0;
|
||||
|
||||
static bool s_pim_filter_primed = false;
|
||||
|
||||
/* ++++ MAIN BODY ++++ */
|
||||
|
||||
/* HELPER FUNCTIONS */
|
||||
|
||||
|
||||
/* METRIC MANIPULATION */
|
||||
static void reset_epoch_metrics(){
|
||||
i_smp = 0; // dont need to reset the accel_data_handler cause we reset
|
||||
// the i_smp, only problem is that slightly off (not quite 1 sec aligned)
|
||||
|
||||
for(int16_t axis = 0; axis < N_AXIS; axis++){
|
||||
// zero out the arrays
|
||||
for(int16_t i = 0; i < SIZE_EPOCH; i++ ){
|
||||
pt_ary[axis][i] = 0;
|
||||
}
|
||||
}
|
||||
for(int16_t i = 0; i < SIZE_EPOCH; i++ ){
|
||||
work_ary[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void reset_summ_metrics(){
|
||||
/* resets all metrics to 0 */
|
||||
for(int16_t axis = 0; axis < N_AXIS; axis++){
|
||||
mean_ary[axis] = 0;
|
||||
pim_ary[axis] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if PEBBLE_APP
|
||||
static void reset_daily_metrics(){
|
||||
// check the previous time tag for this array. Roll the number
|
||||
// of days off that has passed since it was last written to.
|
||||
// BE sure to zero out the
|
||||
|
||||
// use
|
||||
|
||||
// push the days back by one on the
|
||||
|
||||
// update the array tag to the current time (so, a little unintuitive)
|
||||
|
||||
// add the past day's summaries to the history
|
||||
|
||||
// within the first 5 minutes of the day, reset the daily summaries
|
||||
// stepc_daily = 0;
|
||||
persist_write_int(DAILY_STEPC_PERSIST_KEY,0);
|
||||
persist_write_int(DAILY_x1000_KCAL_PERSIST_KEY,0);
|
||||
|
||||
// shift the daily ratings over by one
|
||||
struct pinteract_state pis = get_pinteract_state();
|
||||
struct daily_acti da = get_daily_acti();
|
||||
for(int8_t i = (NUM_DAYS_HISTORY-1); i > 0; i--){
|
||||
pis.pi_11[i] = pis.pi_11[i-1];
|
||||
da.steps[i] = da.steps[i-1];
|
||||
da.kcal[i] = da.kcal[i-1];
|
||||
}
|
||||
persist_write_data(PINTERACT_STATE_PERSIST_KEY, &pis, sizeof(pis));
|
||||
persist_write_data(DAILY_ACTI_PERSIST_KEY, &da, sizeof(da));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* APPMESSAGE MANANGMENT VIA PERSISTENT DATA */
|
||||
|
||||
static void write_blk_buf_to_persist(){
|
||||
/* the persist_read_int(I_BLK_PERSIST_KEY) is NOT a count, it is the current index
|
||||
* but 1-indexced, so 1 is the first block and zero is the empty state */
|
||||
|
||||
if(persist_read_int(I_BLK_PERSIST_KEY) < N_BLK_PERSIST){
|
||||
// set the index of the current block
|
||||
persist_write_int(I_BLK_PERSIST_KEY,persist_read_int(I_BLK_PERSIST_KEY)+1);
|
||||
persist_write_data(persist_read_int(I_BLK_PERSIST_KEY),
|
||||
blk_buf,((SIZE_SUMM*N_SUMM_BLK)+SIZE_BLK_HEAD));
|
||||
}
|
||||
|
||||
/* attempt to send a message if bluetooth connection is there */
|
||||
if(bluetooth_connection_service_peek()){
|
||||
// attempt to send all data to phone
|
||||
if(summ_since_trans_server < SUMM_BTWN_TRANSMIT_SERVER){
|
||||
persist_write_int(WORKER_START_FORE_APP_REASON_PERSIST_KEY,
|
||||
WFAWR_PUSH_ALL_DATA_TO_PHONE);
|
||||
}else{
|
||||
/* >>>>> EXECUTE, SEND TO SERVER <<<<< */
|
||||
persist_write_int(WORKER_START_FORE_APP_REASON_PERSIST_KEY,
|
||||
WFAWR_PUSH_ALL_DATA_TO_SERVER);
|
||||
summ_since_trans_server = 0; // once try to go to server, reset
|
||||
}
|
||||
worker_launch_app();
|
||||
}else if( persist_read_int(I_BLK_PERSIST_KEY) >= (N_BLK_PERSIST-1) ){
|
||||
// if the I_BLK_PERSIST_KEY is greater than 90% of storage, then prompt
|
||||
// that need to connect the phone
|
||||
|
||||
persist_write_int(WORKER_START_FORE_APP_REASON_PERSIST_KEY,
|
||||
WFAWR_MEMORY_LOW_REMINDER);
|
||||
worker_launch_app();
|
||||
}
|
||||
// else if(){
|
||||
// // reset the counter for consecutive summaries
|
||||
// persist_write_int(WORKER_START_FORE_APP_REASON_PERSIST_KEY,
|
||||
// WFAWR_WEAR_REMINDER);
|
||||
// worker_launch_app();
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* SUMMARY DATALOGGING */
|
||||
|
||||
static void summ_datalog(){
|
||||
|
||||
static uint16_t i_summ_blk = 0; // initialize the summ_blk index to 0
|
||||
|
||||
/* >>>>> START MODIFY BLOCK HEADER, TIMESTAMP AND MOOD <<<<< */
|
||||
// add the timestamp at the top of first block and reset the mood index
|
||||
if(i_summ_blk == 0){
|
||||
write_time_to_array_head(time(NULL),blk_buf);
|
||||
blk_buf[4] = CUR_PK_VERSION;
|
||||
}
|
||||
|
||||
/* >>>>> START WRITING REGULAR ACTIGRAPHY DATA <<<<<*/
|
||||
/* WRITE DATA TO INDIVIDUAL SUMMARY BODIES */
|
||||
int16_t offset = (SIZE_SUMM*i_summ_blk + SIZE_BLK_HEAD);
|
||||
// write orientation
|
||||
blk_buf[offset + 0] = (uint8_t) orient_encode(mean_ary, N_ANG);
|
||||
// write vmcpm
|
||||
blk_buf[offset + 1] = (uint8_t) compressed_vmc(pim_ary);
|
||||
|
||||
// persist_write_int(DAILY_x1000_KCAL_PERSIST_KEY,calc_real_vmc(pim_ary)*1000);
|
||||
|
||||
/* >>>>> CALCULATE MET/MOTION KCAL AND UPDATE PERSIST <<<<< */
|
||||
// calculate the real counts, r_c_ary
|
||||
uint32_t r_c_ary[3];
|
||||
for(int16_t axis = 0; axis < 3; axis++){ r_c_ary[axis] = calc_real_c(pim_ary[axis]); }
|
||||
//calculate the kcal for this minute
|
||||
uint32_t x1000_kcal_min = calc_x1000_kcal(r_c_ary);
|
||||
persist_write_int(DAILY_x1000_KCAL_PERSIST_KEY,
|
||||
(x1000_kcal_min
|
||||
+ persist_read_int(DAILY_x1000_KCAL_PERSIST_KEY) ));
|
||||
x1000_kcal_blk += x1000_kcal_min;
|
||||
// >> Write the step counts : finish a section of summaries, write stepc
|
||||
// we write the steps directly here because we dont want to have another
|
||||
// array to track the size, etc, and add extra indirection. Moreover
|
||||
// it keeps the theme of writing regular occuring data in this seciont.
|
||||
// > (i_summ_blk + 1)%(N_SUMM_BLK/N_STEPC_BLK) == 0) --> that
|
||||
// N_SUMM_BLK/N_STEPC_BLK is # of SUMMaries between writing the
|
||||
// step_count to the BLK.
|
||||
// > Hence N_SUMM_BLK must be divisable by N_STEPC_BLK. Also
|
||||
// (i_summ_blk + 1) accounts for the 0 indexing.
|
||||
// Hence, at the START, where
|
||||
// i_summ_blk = 0, we have
|
||||
// (i_summ_blk+1) % (N_SUMM_BLK/N_STEPC_BLK) == 1
|
||||
// and at the END, where:
|
||||
// i_summ_blk = (N_SUMM_BLK - 1), then
|
||||
// (i_summ_blk + 1)%(N_SUMM_BLK/N_STEPC_BLK) == 0
|
||||
if( (i_summ_blk + 1)%(N_SUMM_BLK/N_STEPC_BLK) == 0){
|
||||
// as ( (i_summ_blk + 1)%(N_SUMM_BLK/N_STEPC_BLK) == 0) we have
|
||||
// that (i_summ_blk/(N_SUMM_BLK/N_STEPC_BLK)) rounds down, and
|
||||
blk_buf[(i_summ_blk/(N_SUMM_BLK/N_STEPC_BLK)) + SIZE_BLK_TIME + 2] =
|
||||
compressed_stepc(stepc, N_SUMM_BLK/N_STEPC_BLK);
|
||||
stepc = 0;
|
||||
}
|
||||
/* >>>>> END WRITING REGULAR ACTIGRAPHY DATA <<<<<*/
|
||||
|
||||
/* >>>>> INCREMENT THE SUMM COUNTER IN THE blk_buf <<<<< */
|
||||
i_summ_blk += 1;
|
||||
/* >>>>> INCREMENT NUMBER OF SUMM SINCE LAST TRANSMIT TO SERVER <<<<< */
|
||||
summ_since_trans_server += 1;
|
||||
/* >>>>> WRITE FULL blk_buf TO am_buf AND SEND TO SERVER <<<<< */
|
||||
if( i_summ_blk >= N_SUMM_BLK){
|
||||
/* write the last hours total calories */
|
||||
blk_buf[5] = compressed_x1000_kcal(x1000_kcal_blk,N_SUMM_BLK);
|
||||
x1000_kcal_blk = 0;
|
||||
/* reset the summ counter */
|
||||
i_summ_blk = 0;
|
||||
/* write to appmessage dict cause have full blk_buf */
|
||||
write_blk_buf_to_persist();
|
||||
}
|
||||
|
||||
//* >>>>> WRITE THE CURRENT KCAL and STEPS to CURRENT Daily Acti history <<<<< */
|
||||
struct daily_acti da = get_daily_acti();
|
||||
da.steps[0] = isqrt(persist_read_int(DAILY_STEPC_PERSIST_KEY));
|
||||
da.kcal[0] = isqrt(persist_read_int(DAILY_x1000_KCAL_PERSIST_KEY)/1000);
|
||||
persist_write_data(DAILY_ACTI_PERSIST_KEY, &da, sizeof(da));
|
||||
}
|
||||
#endif // PEBBLE_APP
|
||||
|
||||
/* ACCELEROMETER HANDLING */
|
||||
|
||||
static void epoch_analysis(){
|
||||
if (i_smp == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* WEAR TIME CALCULATION, NO THRESHOLD */
|
||||
uint32_t pim_5sec_ary[3] = {0};
|
||||
|
||||
// If this is the first epoch after an init, we need to prime the butterworth filter used
|
||||
// by prv_pim_filter to avoid getting jumps in VMC due to the discontinuity
|
||||
if (!s_pim_filter_primed) {
|
||||
for (int16_t axis = 0; axis < 3; axis++) {
|
||||
pim_filt_prime(&pt_ary[axis][0], SMP_HZ, axis);
|
||||
}
|
||||
s_pim_filter_primed = true;
|
||||
}
|
||||
|
||||
/* CALCULATE THE AXIS DEPENDENT METRICS */
|
||||
for(int16_t axis = 0; axis < N_AXIS; axis++){
|
||||
// note: move the array ptr by i_smp to give the next start of data array
|
||||
// add the local mean to the global mean array, additively
|
||||
mean_ary[axis] += mean_l1_stat(pt_ary[axis], N_SMP_EPOCH);
|
||||
|
||||
/* CALCULATE THE 1 SECOND METRICS */
|
||||
uint32_t pim_test = 0;
|
||||
// calculate the local pim each 1sec basis: N_SMP_EPOCH/SMP_HZ = num of sec in epoch
|
||||
for(int16_t sec_i = 0; sec_i < (i_smp/SMP_HZ); sec_i++){
|
||||
pim_test = pim_filt(pt_ary[axis] + (sec_i*SMP_HZ), SMP_HZ,axis ); // raw PIM
|
||||
|
||||
// Thresholded pim for the VMCPM calculation, Actigraph equivalent
|
||||
pim_ary[axis] += pim_test; // test if PIM above threshold
|
||||
|
||||
// pim step count analysis
|
||||
pim_5sec_ary[axis] += pim_test;
|
||||
}
|
||||
}
|
||||
|
||||
/* CALCULATE ACCELERATION MAGNITUDE METRICS */
|
||||
// NOTE, we store acceleration magnitude in work vector, original pt_ary
|
||||
// arrays are unmodifed for future use.
|
||||
vm_accel(pt_ary, work_ary, MAX_VM, i_smp); // write vm into work_ary
|
||||
|
||||
/* CALCULATE STEP COUNT FOR 5-SEC TERM, UPDATE PERSIST */
|
||||
uint16_t stepc_tmp = calc_stepc_5sec(work_ary, i_smp, FFT_PWR_TWO, pim_5sec_ary, FFT_SCL);
|
||||
// // +++++++++++++++++++++++++++++++++++
|
||||
// // EXAMPLE for START/STOP problem
|
||||
// int16_t tmp = stepc_tmp;
|
||||
// if((stepc_prev_5sec==0) && (stepc_tmp >0)){
|
||||
// // non-walking to walking
|
||||
// stepc_tmp += (stepc_tmp)/2; // add 1/3 current period to previous period
|
||||
// }else if((stepc_prev_5sec > 0) && (stepc_tmp == 0)){
|
||||
// // walking to non-walking
|
||||
// stepc_tmp += (stepc_prev_5sec)/2; // add 1/3 prev period to current period
|
||||
// }
|
||||
// stepc_prev_5sec = tmp;
|
||||
// // END EXAMPLE
|
||||
// // +++++++++++++++++++++++++++++++++++
|
||||
// +++++++++++++++++++++++++++++++++++
|
||||
// EXAMPLE for START/STOP problem
|
||||
int16_t tmp = stepc_tmp;
|
||||
if((stepc_prev_10sec==0) && (stepc_prev_5sec>0) && (stepc_tmp >0)){
|
||||
// non-walking to walking
|
||||
stepc_tmp += (stepc_tmp)/2; // add 1/2 current period to previous period
|
||||
}else if( (stepc_prev_10sec > 0) && (stepc_prev_5sec > 0) && (stepc_tmp == 0)){
|
||||
// walking to non-walking
|
||||
stepc_tmp += (stepc_prev_5sec)/2; // add 1/2 prev period to current period
|
||||
}
|
||||
stepc_prev_10sec = stepc_prev_5sec;
|
||||
stepc_prev_5sec = tmp;
|
||||
// END EXAMPLE
|
||||
// +++++++++++++++++++++++++++++++++++
|
||||
|
||||
// UPDATE STEPS
|
||||
stepc += stepc_tmp;
|
||||
// stepc_daily += stepc_tmp;
|
||||
#if PEBBLE_APP
|
||||
persist_write_int(DAILY_STEPC_PERSIST_KEY,
|
||||
persist_read_int(DAILY_STEPC_PERSIST_KEY) + stepc_tmp);
|
||||
#endif
|
||||
|
||||
// !! RESET THE EPOCH . At the end of each epoch analysis, we ALWAYS need to
|
||||
// go back to i_smp=0, regardless of where in the cycle we are
|
||||
reset_epoch_metrics();
|
||||
}
|
||||
|
||||
#if PEBBLE_APP
|
||||
void tick_summ_datalog_second_hander(struct tm *tick_time, TimeUnits units_changed){
|
||||
static int8_t cur_min = -1; // this tracks the current min, 0-59 values
|
||||
// this is to protect against summ_datalog() being called more than once a min
|
||||
|
||||
|
||||
/* >>>>> EXECUTE TOP OF EACH MINUTE, XX:XX:00 <<<<< */
|
||||
// ALSO, only execute it it is a new second/new minute
|
||||
if( (tick_time->tm_sec == 0) && (tick_time->tm_min != cur_min) ){
|
||||
// reset the minute gate
|
||||
cur_min = tick_time->tm_min;
|
||||
/* perform the epoch analysis */
|
||||
epoch_analysis();
|
||||
/* write the summary to the persist storage */
|
||||
summ_datalog();
|
||||
/* reset the summary metric arrays after each write to storage */
|
||||
reset_summ_metrics();
|
||||
|
||||
/* >>>>> REMINDERS <<<<< */
|
||||
/* WEAR TIME */
|
||||
/* MEMORY WARNING */
|
||||
}
|
||||
|
||||
/* >>>>> RESET THE DAILY METRICS AND CHANGE LONG TERM DATA @ 12:01AM <<<<< */
|
||||
if( (tick_time->tm_hour == 0 ) && (tick_time->tm_min == 1 ) && (tick_time->tm_sec == 0 )){
|
||||
reset_daily_metrics();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void accel_data_handler(AccelData *data, uint32_t num_samples ){
|
||||
/* WRITE THE SAMPLES INTO THE X,Y,Z STORAGE ARRAYS*/
|
||||
for (int16_t i = 0; i < (int16_t) num_samples; i++){
|
||||
/* Divide each sample by LVL_SCL to prevent int overflow in wavelet compression */
|
||||
pt_ary[0][i + i_smp] = (data[i].x + LVL_SCL / 2) >> LVL_SHIFT;
|
||||
pt_ary[1][i + i_smp] = (data[i].y + LVL_SCL / 2) >> LVL_SHIFT;
|
||||
pt_ary[2][i + i_smp] = (data[i].z + LVL_SCL / 2) >> LVL_SHIFT;
|
||||
}
|
||||
|
||||
/* INCREMENT THE SAMPLES INDEX */
|
||||
i_smp += SMP_HZ; // perhaps i_smp += num_samples; in case non-uniform?
|
||||
|
||||
/* when attain N_SMP_EPOCH samples, perform the various summary statistics , write epoch-data to log */
|
||||
if(i_smp >= N_SMP_EPOCH){
|
||||
epoch_analysis();
|
||||
/* RESET THE SAMPLE INDEX*/
|
||||
}
|
||||
}
|
||||
|
||||
#if PEBBLE_APP
|
||||
/* BLUETOOTH CONNECTION SERVICE HANDLER*/
|
||||
void worker_bt_service_handler(bool connected){
|
||||
if(connected){
|
||||
// set the foreground app start by worker info persistant storage id
|
||||
// try to send all data to phone
|
||||
persist_write_int(WORKER_START_FORE_APP_REASON_PERSIST_KEY,
|
||||
WFAWR_PUSH_ALL_DATA_TO_SERVER);
|
||||
worker_launch_app();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* INITIALIZATION AND MAIN WORKER LOOP */
|
||||
|
||||
static void init_mem_log(){
|
||||
/* initializing x,y,z storage arrays and work array */
|
||||
for(int16_t axis = 0; axis < N_AXIS; axis++){
|
||||
pt_ary[axis] = (int16_t*) calloc(SIZE_EPOCH, sizeof(int16_t));
|
||||
}
|
||||
/* initialize the work array */
|
||||
work_ary = (int16_t*) calloc(SIZE_EPOCH, sizeof(int16_t));
|
||||
/* initalize the block buffer here */
|
||||
blk_buf = (uint8_t*) calloc(((SIZE_SUMM*N_SUMM_BLK)+SIZE_BLK_HEAD), sizeof(uint8_t));
|
||||
#if PEBBLE_APP
|
||||
/* save the size of the block buffer (# of bytes long) to persistent storage */
|
||||
persist_write_int(BUF_SIZE_PERSIST_KEY,((SIZE_SUMM*N_SUMM_BLK)+SIZE_BLK_HEAD));
|
||||
#endif
|
||||
pim_filt_init();
|
||||
s_pim_filter_primed = false;
|
||||
}
|
||||
|
||||
|
||||
#if PEBBLE_APP
|
||||
static void init() {
|
||||
init_mem_log();
|
||||
// accel_data_service_subscribe(SMP_HZ, accel_data_handler);
|
||||
// accel_service_set_sampling_rate(ACCEL_SAMPLING_25HZ);
|
||||
|
||||
// subscribe the summ_datalog tick handler
|
||||
// NOTE : we need to be sure to have second-level accuracy, so given the bugs
|
||||
// with the MINUTE_UNIT timer, we assume that we need to call every second
|
||||
// NOTE! we use SECOND_UNIT, SECOND_UNIT is CORRECT!!
|
||||
tick_timer_service_subscribe(SECOND_UNIT, tick_summ_datalog_second_hander);
|
||||
|
||||
// subscribe to the accelerometer handler
|
||||
accel_data_service_subscribe(SMP_HZ, accel_data_handler);
|
||||
accel_service_set_sampling_rate(ACCEL_SAMPLING_25HZ);
|
||||
|
||||
// set the bluetooth state change to also send the data
|
||||
bluetooth_connection_service_subscribe(worker_bt_service_handler);
|
||||
|
||||
// init the learning algorithms params, if HAS NOT been init'ed
|
||||
// struct acticlass_learn_alg_state aclas;
|
||||
// persist_read_data(ACTICLASS_LEARN_ALG_STATE_PERSIST_KEY, &aclas, sizeof(aclas));
|
||||
// if( !aclas.init_alg){
|
||||
// init_learn_alg1_stepc_posts_ps();
|
||||
// }
|
||||
}
|
||||
|
||||
static void deinit() {
|
||||
accel_data_service_unsubscribe();
|
||||
tick_timer_service_unsubscribe();
|
||||
/* free the malloc'ed x,y,z arrays and work array */
|
||||
for(int16_t axis = 0; axis < N_AXIS; axis++){
|
||||
free(pt_ary[axis]);
|
||||
}
|
||||
free(work_ary);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
init();
|
||||
worker_event_loop();
|
||||
deinit();
|
||||
}
|
||||
#endif // PEBBLE_APP
|
||||
|
||||
void ref_init(void) {
|
||||
init_mem_log();
|
||||
stepc = 0;
|
||||
stepc_prev_10sec = 0;
|
||||
stepc_prev_5sec = 0;
|
||||
}
|
||||
|
||||
int ref_accel_data_handler(AccelData *data, uint32_t num_samples) {
|
||||
accel_data_handler(data, num_samples );
|
||||
return stepc;
|
||||
}
|
||||
|
||||
int ref_finish_epoch(void) {
|
||||
epoch_analysis();
|
||||
return stepc;
|
||||
}
|
||||
|
||||
void ref_minute_stats(uint8_t *orientation, uint8_t *vmc) {
|
||||
*orientation = orient_encode(mean_ary, N_ANG);
|
||||
*vmc = compressed_vmc(pim_ary);
|
||||
|
||||
uint32_t r_c_ary[3];
|
||||
for (int16_t axis = 0; axis < 3; axis++) {
|
||||
r_c_ary[axis] = calc_real_c(pim_ary[axis]);
|
||||
}
|
||||
uint32_t kcals_min = calc_x1000_kcal(r_c_ary);
|
||||
|
||||
PBL_LOG(LOG_LEVEL_DEBUG, "minute_stats vmc: %d, orientation:0x%x, calories: %d",
|
||||
(int)*vmc, (int)*orientation, (int)kcals_min);
|
||||
|
||||
reset_summ_metrics();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// void tick_summ_datalog_hander(struct tm *tick_time, TimeUnits units_changed){
|
||||
// static int8_t cur_min = -1; // this tracks the current min, 0-59 values
|
||||
// // this is to protect against summ_datalog() being called more than once a min
|
||||
//
|
||||
// /* >>>>> EXECUTE TOP OF EACH SECOND, XX:XX:XX <<<<< */
|
||||
//
|
||||
// /* >>>>> EXECUTE TOP OF EACH MINUTE, XX:XX:00 <<<<< */
|
||||
// if( (tick_time->tm_sec == 0) && (tick_time->tm_min != cur_min)){
|
||||
// // reset the minute gate
|
||||
// cur_min = tick_time->tm_min;
|
||||
// /* perform the epoch analysis */
|
||||
// epoch_analysis();
|
||||
// /* write the summary to the persist storage */
|
||||
// summ_datalog();
|
||||
// /* reset the summary metric arrays after each write to storage */
|
||||
// reset_summ_metrics();
|
||||
// }
|
||||
//
|
||||
// /* >>>>> RESET THE DAILY METRICS AND CHANGE LONG TERM DATA @ 12:01AM <<<<< */
|
||||
// if( (tick_time->tm_hour == 0 ) && (tick_time->tm_min < 1 )){
|
||||
// reset_daily_metrics();
|
||||
// }
|
||||
// /* >>>>> EXECUTE, SEND TO SERVER <<<<< */
|
||||
// if( summ_since_trans_server > SUMM_BTWN_TRANSMIT_SERVER){
|
||||
// persist_write_int(WORKER_START_FORE_APP_REASON_PERSIST_KEY, 2);
|
||||
// summ_since_trans_server = 0; // once try to go to server, reset
|
||||
// }
|
||||
// }
|
25
third_party/Kraepelin/kraepelin_reference/ProjectK_worker.h
vendored
Normal file
25
third_party/Kraepelin/kraepelin_reference/ProjectK_worker.h
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "applib/accel_service.h"
|
||||
|
||||
#include "constants_worker.h"
|
||||
#include "helper_worker.h"
|
||||
#include "fourier.h"
|
||||
#include "raw_stats.h"
|
||||
|
||||
|
||||
static void write_blk_buf_to_persist();
|
||||
|
||||
static void summ_datalog();
|
||||
|
||||
static void reset_summ_metrics();
|
||||
|
||||
static void accel_data_handler(AccelData *data, uint32_t num_samples );
|
||||
|
||||
static void init_mem_log();
|
||||
|
||||
static void init();
|
||||
|
||||
static void deinit();
|
||||
|
||||
int main(void);
|
168
third_party/Kraepelin/kraepelin_reference/constants_worker.h
vendored
Normal file
168
third_party/Kraepelin/kraepelin_reference/constants_worker.h
vendored
Normal file
|
@ -0,0 +1,168 @@
|
|||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* +++++++++++++++ PERSISTANT STORAGE KEYS +++++++++++++++ */
|
||||
|
||||
// +++++++ RESERVED KEYS
|
||||
// REMEMBER!!! keys 1-20 are reserved for the actigraphy keys
|
||||
|
||||
// +++++++ intra-app messaging
|
||||
static const int16_t WORKER_START_FORE_APP_REASON_PERSIST_KEY = 120;
|
||||
|
||||
// +++++++ App State
|
||||
static const int16_t PINTERACT_STATE_PERSIST_KEY = 130;
|
||||
static const int16_t CONFIG_WAKEUP_IDS_PERSIST_KEY = 131;
|
||||
static const int16_t ACTIVE_WAKEUP_CONFIG_I_PERSIST_KEY = 132;
|
||||
static const int16_t ACTICLASS_LEARN_ALG_STATE_PERSIST_KEY = 133;
|
||||
|
||||
|
||||
// +++++++ Configuration Data
|
||||
static const int16_t CONFIG_GENERAL_PERSIST_KEY = 180;
|
||||
static const int16_t CONFIG_WAKEUP_PERSIST_KEY = 181;
|
||||
static const int16_t PK_VERSION_PERSIST_KEY = 183;
|
||||
|
||||
|
||||
// +++++++ Interaction Data
|
||||
static const int16_t PIRPS_B1_PERSIST_KEY = 190; // Patient Response Pesistant Storage, Block 1
|
||||
static const int16_t PIRPS_B2_PERSIST_KEY = 191; // Patient Response Pesistant Storage, Block 2
|
||||
|
||||
|
||||
// +++++++ Continuous Data
|
||||
static const int16_t BUF_SIZE_PERSIST_KEY = 200;
|
||||
static const int16_t I_BLK_PERSIST_KEY = 201;
|
||||
// continuous daily metrics
|
||||
static const int16_t DAILY_STEPC_PERSIST_KEY = 210;
|
||||
static const int16_t DAILY_x1000_KCAL_PERSIST_KEY = 211;
|
||||
static const int16_t DAILY_ACTI_PERSIST_KEY = 212;
|
||||
|
||||
|
||||
// +++++++ Long Term Data
|
||||
static const int16_t DAILY_SUMMARY_WEEKS_PERSIST_KEY = 220;
|
||||
|
||||
|
||||
// +++++++ General Constants
|
||||
// # DEFINED CONSTANTS
|
||||
static const uint32_t NUM_SEC_IN_DAY = 24*60*60;
|
||||
static const uint32_t NUM_SEC_IN_WEEK = 7*24*60*60;
|
||||
static const uint8_t CUR_PK_VERSION = 6;
|
||||
|
||||
|
||||
// +++++++ Memory Constraints
|
||||
static const uint16_t N_B_TRANSMIT_CODE = 800;
|
||||
static const uint16_t N_B_REMINDER_CODE = 400;
|
||||
|
||||
|
||||
|
||||
|
||||
/* +++++++++++++++ ENUMERATED TYPES +++++++++++++++ */
|
||||
|
||||
enum WorkerForeAppWakeupReason{
|
||||
WFAWR_DO_NOTHING,
|
||||
WFAWR_PUSH_ALL_DATA_TO_SERVER,
|
||||
WFAWR_PUSH_ALL_DATA_TO_PHONE,
|
||||
WFAWR_MEMORY_LOW_REMINDER,
|
||||
WFAWR_WEAR_REMINDER,
|
||||
NUM_WFAWR
|
||||
};
|
||||
|
||||
enum TransmitReason{
|
||||
TR_PUSH_NULL,
|
||||
TR_PUSH_ALL_DATA_TO_SERVER,
|
||||
TR_PUSH_ALL_DATA_TO_PHONE,
|
||||
NUM_TR
|
||||
};
|
||||
|
||||
enum AppMessageKeys{
|
||||
AMKEY_NULL,
|
||||
AMKEY_PUSHTOSERVER,
|
||||
AMKEY_ACTI,
|
||||
AMKEY_PINTERACT,
|
||||
AMKEY_CONFIG_GENERAL,
|
||||
AMKEY_CONFIG_WAKEUP,
|
||||
NUM_AMKEY
|
||||
};
|
||||
|
||||
enum ReminderReason{
|
||||
RR_NULL,
|
||||
RR_MEMORY_LOW,
|
||||
RR_WEAR,
|
||||
NUM_RR
|
||||
};
|
||||
|
||||
enum ActivityClass {
|
||||
NO_ACTICLASS,
|
||||
SLOW_WALK,
|
||||
WALK,
|
||||
FAST_WALK,
|
||||
RUN,
|
||||
FAST_RUN,
|
||||
NUM_ACTICLASS
|
||||
};
|
||||
|
||||
enum ActivityClassLearnFeatures {
|
||||
ACLF_VMC,
|
||||
ACLF_FFT_SCORE,
|
||||
NUM_ACLF
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* +++++++++++++++ STRUCTURES +++++++++++++++ */
|
||||
|
||||
// NOTES
|
||||
// uint16_t daily_steps;
|
||||
// total daily steps
|
||||
// uint16_t daily_motion_kcal;
|
||||
// daily calories estimated expended only through motion
|
||||
// uint16_t daily_sleep_tot_min;
|
||||
// sleep assigned for the 16 hours previous to the time when the
|
||||
// person said that they arose, AND the DAY to which these minutes
|
||||
// are assigned is the one that the 16 hours ENDED ON.
|
||||
// uint16_t daily_arise_time_min;
|
||||
// time when person said getitng up for the day, triggered by a sudden
|
||||
// increase in the number od steps
|
||||
// counts
|
||||
|
||||
struct config_general{
|
||||
uint16_t pheight_cm; // cm;
|
||||
uint16_t pweight_kg; // kg;
|
||||
uint8_t stepc_fft_thres0[2]; // percent*100 of energy in 0.3-4hz band
|
||||
uint16_t stepc_vma_thres0;
|
||||
uint16_t stepc_vmc_thres0;
|
||||
|
||||
uint16_t wear_class_thres;
|
||||
uint16_t pts_goal;
|
||||
|
||||
}__attribute__((__packed__));
|
||||
|
||||
|
||||
|
||||
#define NUM_DAYS_HISTORY 8
|
||||
|
||||
struct daily_acti{
|
||||
uint16_t steps[NUM_DAYS_HISTORY]; // total daily steps
|
||||
uint16_t kcal[NUM_DAYS_HISTORY]; // daily calories estimated expended only through motion
|
||||
}__attribute__((__packed__));
|
||||
|
||||
struct pinteract_state{
|
||||
int8_t pi_11[NUM_DAYS_HISTORY]; // can make this a uint8_t array for last 10 days
|
||||
int16_t pi_12;
|
||||
int16_t pi_13;
|
||||
int16_t pi_14;
|
||||
int16_t pi_15;
|
||||
}__attribute__((__packed__));
|
||||
|
||||
|
||||
struct acticlass_learn_alg_state{
|
||||
bool init_alg;
|
||||
uint16_t f_mean[NUM_ACTICLASS][NUM_ACLF];
|
||||
uint16_t f_std[NUM_ACTICLASS][NUM_ACLF];
|
||||
}__attribute__((__packed__));
|
||||
|
||||
|
||||
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
|
||||
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
|
||||
/* +++++++++++++++++++++ BACKGROUND APP CONSTANTS ONLY +++++++++++++++++++++++ */
|
||||
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
|
||||
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
|
117
third_party/Kraepelin/kraepelin_reference/fourier.c
vendored
Normal file
117
third_party/Kraepelin/kraepelin_reference/fourier.c
vendored
Normal file
|
@ -0,0 +1,117 @@
|
|||
/* Project Kraepelin, Main file
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015, Nathaniel T. Stockham
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
This license is taken to apply to any other files in the Project Kraepelin
|
||||
Pebble App roject.
|
||||
*/
|
||||
|
||||
|
||||
// #include <pebble_worker.h>
|
||||
#include "fourier.h"
|
||||
#include "helper_worker.h"
|
||||
|
||||
void fft_2radix_real(int16_t *d, int16_t dlenpwr){
|
||||
|
||||
/* +++++++++++ REAL-VALUED, IN-PLACE, 2-RADIX FOURIER TRANSFORM +++++++++++
|
||||
*
|
||||
* This implementation of the fourier transform is taken directly from
|
||||
* Henrik V. Sorensen's 1987 paper "Real-valued Fast Fourier Tranform
|
||||
* Algorithms" with slight modifications to allow use of Pebble's cos and
|
||||
* sin lookup functions with input range of 0 to 2*pi angle scaled to
|
||||
* 0 to 65536 and output range of -1 to 1 scaled to -65535 to 65536. This
|
||||
* descretization introduces some discrepancies between the results of this
|
||||
* function and the floating point equivalents that are not important for its
|
||||
* use here, but nonetheless documented in the accompaning Julia test code.
|
||||
* INPUT
|
||||
* d = input signal array pointer
|
||||
* dlenpwr = the exponent of the array length, ie: array length = 2^dlenpwr
|
||||
* OUTPUT
|
||||
* d = fourier tranformed array pointer, with array of real coefficents of form
|
||||
* [Re(0), Re(1),..., Re(N/2-1), Re(N/2), Im(N/2-1),..., Im(1)]
|
||||
*/
|
||||
|
||||
int16_t n = pow_int(2,dlenpwr);
|
||||
int16_t j = 1;
|
||||
int16_t n1 = n -1;
|
||||
int16_t k,dt;
|
||||
|
||||
for(int16_t i = 1; i <= n1; i++){
|
||||
if(i < j){
|
||||
dt = d[j-1];
|
||||
d[j-1] = d[i-1];
|
||||
d[i-1] = dt;
|
||||
}
|
||||
k = n/2;
|
||||
while(k < j){
|
||||
j = j - k;
|
||||
k = k/2;
|
||||
}
|
||||
j = j + k;
|
||||
}
|
||||
|
||||
for(int16_t i = 1; i <= n; i += 2){
|
||||
dt = d[i-1];
|
||||
d[i-1] = dt + d[i];
|
||||
d[i] = dt - d[i];
|
||||
}
|
||||
|
||||
int16_t n2 = 1;
|
||||
int16_t n4,i1,i2,i3,i4,t1,t2;
|
||||
|
||||
int32_t E,A,ss,cc;
|
||||
|
||||
|
||||
for(int16_t k = 2; k <= dlenpwr ; k++){
|
||||
n4 = n2;
|
||||
n2 = 2*n4;
|
||||
n1 = 2*n2;
|
||||
E = TRIG_MAX_ANGLE/n1;
|
||||
|
||||
for(int16_t i = 1; i<= n; i+=n1 ){
|
||||
dt = d[i-1];
|
||||
d[i-1] = dt + d[i+n2-1];
|
||||
d[i+n2-1] = dt - d[i+n2-1];
|
||||
d[i+n4+n2-1] = - d[i+n4+n2-1];
|
||||
A = E;
|
||||
for(int16_t j = 1; j <= (n4-1); j++){
|
||||
i1 = i + j;
|
||||
i2 = i - j + n2;
|
||||
i3 = i + j + n2;
|
||||
i4 = i - j + n1;
|
||||
|
||||
ss = sin_lookup(A);
|
||||
cc = cos_lookup(A);
|
||||
|
||||
A = A + E;
|
||||
|
||||
t1 = (int16_t) ((d[i3-1]*cc + d[i4-1]*ss)/TRIG_MAX_ANGLE);
|
||||
t2 = (int16_t) ((d[i3-1]*ss - d[i4-1]*cc)/TRIG_MAX_ANGLE);
|
||||
|
||||
d[i4-1] = d[i2-1] - t2;
|
||||
d[i3-1] = -d[i2-1] - t2;
|
||||
d[i2-1] = d[i1-1] - t1;
|
||||
d[i1-1] = d[i1-1] + t1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
third_party/Kraepelin/kraepelin_reference/fourier.h
vendored
Normal file
7
third_party/Kraepelin/kraepelin_reference/fourier.h
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void fft_2radix_real(int16_t *d, int16_t dlenpwr);
|
||||
|
1004
third_party/Kraepelin/kraepelin_reference/raw_stats.c
vendored
Normal file
1004
third_party/Kraepelin/kraepelin_reference/raw_stats.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
64
third_party/Kraepelin/kraepelin_reference/raw_stats.h
vendored
Normal file
64
third_party/Kraepelin/kraepelin_reference/raw_stats.h
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
#pragma once
|
||||
#if PEBBLE_APP
|
||||
#include <pebble_worker.h>
|
||||
#endif
|
||||
#include "constants_worker.h"
|
||||
#include "helper_worker.h"
|
||||
#include "fourier.h"
|
||||
|
||||
// #include <math.h>
|
||||
typedef signed long long sfxp;
|
||||
typedef unsigned long long ufxp;
|
||||
#define int2sll(X) (((sfxp) (X)) << 32)
|
||||
#define sll2int(X) ((int32_t) ((X) >> 32))
|
||||
|
||||
// scaling constants
|
||||
// 13.5*10, convert the raw pim cpm to the actigraph vmcpm
|
||||
// used for both VMCPM and CPM (cause a linear relation)
|
||||
// static const uint32_t x100_RAW_1G_PIM_CPM_TO_REAL_CPM = 1863;
|
||||
static const uint32_t x100_RAW_1G_PIM_CPM_TO_REAL_CPM = 2408;
|
||||
|
||||
int32_t mean_l1_stat(int16_t *d, int16_t dlen);
|
||||
|
||||
uint32_t pim_filt(int16_t *d, int16_t dlen, int16_t axis);
|
||||
|
||||
uint32_t calc_scaled_vmc(uint32_t *pim_ary);
|
||||
|
||||
uint8_t compressed_vmc(uint32_t *pim_ary);
|
||||
|
||||
uint32_t calc_real_vmc(uint32_t *pim_ary);
|
||||
|
||||
uint32_t calc_real_c(uint32_t pim);
|
||||
|
||||
uint32_t calc_x1000_kcal(uint32_t *pim_ary);
|
||||
|
||||
uint8_t compressed_x1000_kcal(uint32_t x1000_kcal, int16_t num_min);
|
||||
|
||||
uint8_t compressed_stepc(uint32_t stepc, int16_t num_min);
|
||||
|
||||
void vm_accel(int16_t **d, int16_t *w, int16_t max_vm, int16_t dlen);
|
||||
|
||||
void vm_accel_xy(int16_t **d, int16_t *w, int16_t max_vm, int16_t dlen);
|
||||
|
||||
int16_t score_fft_alg_0pad(int16_t *d, int16_t dlen_smp, int16_t dlenpwr_ary, int16_t oflw_scl);
|
||||
|
||||
void get_fftmag_0pad(int16_t *d, int16_t dlen_smp, int16_t dlenpwr_ary, int16_t oflw_scl);
|
||||
|
||||
void get_fftmag_0pad_mean0(int16_t *d, int16_t dlen_smp, int16_t dlenpwr_ary, int16_t oflw_scl);
|
||||
|
||||
uint16_t score_fftmag_hz_rng(int16_t *d, int16_t dlenpwr_ary,int16_t lhz_i,int16_t hhz_i);
|
||||
|
||||
uint16_t score_fftmag_hz_rng_l2(int16_t *d, int16_t dlenpwr_ary,int16_t lhz_i,int16_t hhz_i);
|
||||
|
||||
void filt_hann_win_mean0(int16_t *d, int16_t dlen_smp, int32_t g_fctr);
|
||||
|
||||
int16_t max_mag_hz_0pad(int16_t *d);
|
||||
|
||||
int16_t calc_stepc_5sec(int16_t *work_ary, int16_t dlen_smp, int16_t dlenpwr_ary,
|
||||
uint32_t *pim_5sec_ary, int16_t fft_oflw_scl);
|
||||
|
||||
// int16_t stepc_fftalg_0pad(int16_t *d, int16_t dlen_smp, int16_t dlenpwr_ary, int16_t oflw_scl);
|
||||
|
||||
void pim_filt_init(void);
|
||||
|
||||
void pim_filt_prime(int16_t *d, int16_t dlen, int16_t axis);
|
Loading…
Add table
Add a link
Reference in a new issue