Added option to log accelerometer data to file
[pedometerwidget] / pedometer.py
1 import math
2 import time
3 import logging
4 import gobject
5
6 from threading import Thread
7
8 logger = logging.getLogger("pedometer")
9 logger.setLevel(logging.INFO)
10
11 ch = logging.StreamHandler()
12 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
13 ch.setFormatter(formatter)
14 logger.addHandler(ch)
15
16
17 class PedoIntervalCounter:
18     MIN_THRESHOLD = 500
19     MIN_TIME_STEPS = 0.5
20     x = []
21     y = []
22     z = []
23     t = []
24
25     #TODO: check if last detected step is at the end of the interval
26
27     def __init__(self, coords, tval):
28         self.x = coords[0]
29         self.y = coords[1]
30         self.z = coords[2]
31         self.t = tval
32
33     def calc_mean(self, vals):
34         sum = 0
35         for i in vals:
36             sum+=i
37         if len(vals) > 0:
38             return sum / len(vals)
39         return 0
40
41     def calc_stdev(self, vals):
42         rez = 0
43         mean = self.calc_mean(vals)
44         for i in vals:
45             rez+=pow(abs(mean-i),2)
46         return math.sqrt(rez/len(vals))
47
48     def calc_threshold(self, vals):
49         vmax = max(vals)
50         vmin = min(vals)
51         mean = self.calc_mean(vals)
52         threshold = max (abs(mean-vmax), abs(mean-vmin))
53         return threshold
54
55     def count_steps(self, vals, t):
56         threshold = self.MIN_THRESHOLD
57         mean = self.calc_mean(vals)
58         cnt = 0
59
60         i=0
61         while i < len(vals):
62             if abs(vals[i] - mean) > threshold:
63                 cnt+=1
64                 ntime = t[i] + 0.5
65                 while i < len(vals) and t[i] < ntime:
66                     i+=1
67             i+=1
68         return cnt
69
70     def get_best_values(self, x, y, z):
71         dev1 = self.calc_stdev(x)
72         dev2 = self.calc_stdev(y)
73         dev3 = self.calc_stdev(z)
74         dev_max = max(dev1, dev2, dev3)
75
76         if ( abs(dev1 - dev_max ) < 0.001):
77             logger.info("X chosen as best axis, stdev %f" % dev1)
78             return x
79         elif (abs(dev2 - dev_max) < 0.001):
80             logger.info("Y chosen as best axis, stdev %f" % dev2)
81             return y
82         else:
83             logger.info("Z chosen as best axis, stdev %f" % dev3)
84             return z
85
86     def number_steps(self):
87         vals = self.get_best_values(self.x, self.y, self.z)
88         return self.count_steps(vals, self.t)
89
90 class PedoCounter(Thread):
91     COORD_FNAME = "/sys/class/i2c-adapter/i2c-3/3-001d/coord"
92     COORD_GET_INTERVAL = 0.01
93     COUNT_INTERVAL = 5
94     STEP_LENGTH = 0.5
95
96     counter = 0
97     update_function = None
98
99     def __init__(self, update_function = None):
100         Thread.__init__(self)
101         self.update_function = update_function
102
103     def get_rotation(self):
104         f = open(self.COORD_FNAME, 'r')
105         coords = [int(w) for w in f.readline().split()]
106         f.close()
107         return coords
108
109     def reset_counter(self):
110         counter = 0
111
112     def get_counter(self):
113         return counter
114
115     def start_interval(self):
116         logger.info("New interval started")
117         stime = time.time()
118         t=[]
119         coords = [[], [], []]
120         while len(t) == 0 or t[-1] < 5:
121             x,y,z = self.get_rotation()
122             coords[0].append(int(x))
123             coords[1].append(int(y))
124             coords[2].append(int(z))
125             now = time.time()-stime
126             t.append(now)
127             time.sleep(self.COORD_GET_INTERVAL)
128         pic = PedoIntervalCounter(coords, t)
129         cnt = pic.number_steps()
130
131         logger.info("Number of steps detected for last interval %d, number of coords: %d" % (cnt, len(t)))
132
133         self.counter += cnt
134         logger.info("Total number of steps : %d" % self.counter)
135         return cnt
136
137     def run(self):
138         while 1:
139             last_cnt = self.start_interval()
140             if self.update_function is not None:
141                 gobject.idle_add(self.update_function, self.counter, last_cnt)
142
143     def get_distance(self, steps=None):
144         if steps == None:
145             steps = self.counter
146         return self.STEP_LENGTH * steps;
147
148
149
150
151 if __name__ == "__main__":
152     a = PedoCounter()
153     a.run()