comparison py/utils.py @ 571:ccfaa4351fd8

scale integrate by delay time namedtuple for StepIntegrator
author Matt Johnston <matt@ucc.asn.au>
date Wed, 11 Nov 2015 21:58:38 +0800
parents afe2eb17723e
children 02aff9ff8d24
comparison
equal deleted inserted replaced
570:afe2eb17723e 571:ccfaa4351fd8
5 import select 5 import select
6 import logging 6 import logging
7 import binascii 7 import binascii
8 import json 8 import json
9 import datetime 9 import datetime
10 import collections
10 11
11 D = logging.debug 12 D = logging.debug
12 L = logging.info 13 L = logging.info
13 W = logging.warning 14 W = logging.warning
14 E = logging.error 15 E = logging.error
170 if self(): 171 if self():
171 L(msg + " (log interval %s)" % str(self.limit)) 172 L(msg + " (log interval %s)" % str(self.limit))
172 else: 173 else:
173 D(msg) 174 D(msg)
174 175
176 Period = collections.namedtuple('Period', 'start end')
175 class StepIntegrator(object): 177 class StepIntegrator(object):
176 """ 178 """
177 Takes on/off events and a monotonically increasing timefn. Returns the integral 179 Takes on/off events and a monotonically increasing timefn. Returns the integral
178 of (now-limittime, now) over those events. 180 of (now-limittime, now) over those events.
179 181
208 >>> t = 170 210 >>> t = 170
209 >>> print(s.integrate()) 211 >>> print(s.integrate())
210 0 212 0
211 """ 213 """
212 def __init__(self, timefn, limittime): 214 def __init__(self, timefn, limittime):
213 # _on_periods is a list of [[start, end]]. End is None if still on 215 # _on_periods is a list of [period]. End is None if still on
214 self._on_periods = [] 216 self._on_periods = []
215 self._timefn = timefn 217 self._timefn = timefn
216 self._limittime = limittime 218 self._limittime = limittime
217 219
218 def set_limit(self, limittime): 220 def set_limit(self, limittime):
219 if self._limittime == limittime: 221 if self._limittime == limittime:
220 return 222 return
221 self._limittime = limittime 223 self._limittime = limittime
222 self.trim() 224 self._trim()
223 225
224 def turn(self, value): 226 def turn(self, value):
225 if not self._on_periods: 227 if not self._on_periods:
226 if value: 228 if value:
227 self._on_periods.append([self._timefn(), None]) 229 self._on_periods.append(Period(self._timefn(), None))
228 return 230 return
229 231
230 # state hasn't changed 232 # state hasn't changed
231 on_now = (self._on_periods[-1][1] is None) 233 on_now = (self._on_periods[-1].end is None)
232 if value == on_now: 234 if value == on_now:
233 return 235 return
234 236
235 if value: 237 if value:
236 self._on_periods.append([self._timefn(), None]) 238 self._on_periods.append(Period(self._timefn(), None))
237 else: 239 else:
238 self._on_periods[-1][1] = self._timefn() 240 self._on_periods[-1] = self._on_periods[-1]._replace(end = self._timefn())
239 241
240 def _trim(self): 242 def _trim(self):
241 begin = self._timefn() - self._limittime 243 begin = self._timefn() - self._limittime
242 # shortcut, first start is after begin 244 # shortcut, first start is after begin
243 if not self._on_periods or self._on_periods[0][0] >= begin: 245 if not self._on_periods or self._on_periods[0].start >= begin:
244 return 246 return
245 247
246 new_periods = [] 248 new_periods = []
247 for s, e in self._on_periods: 249 for s, e in self._on_periods:
248 if s == e: 250 if s == e:
249 continue 251 continue
250 elif s >= begin: 252 elif s >= begin:
251 new_periods.append([s,e]) 253 new_periods.append(Period(s,e))
252 elif e is not None and e < begin: 254 elif e is not None and e < begin:
253 continue 255 continue
254 else: 256 else:
255 new_periods.append([begin, e]) 257 new_periods.append(Period(begin, e))
256 self._on_periods = new_periods 258 self._on_periods = new_periods
257 259
258 def integrate(self): 260 def integrate(self):
259 self._trim() 261 self._trim()
260 tot = 0 262 tot = 0