| Index: common/monsoon/monsoon/monsoon_utils.py
 | 
| diff --git a/common/monsoon/monsoon/monsoon_utils.py b/common/monsoon/monsoon/monsoon_utils.py
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..905792f2a12afb1f19695bb6a648b2add7d2a93f
 | 
| --- /dev/null
 | 
| +++ b/common/monsoon/monsoon/monsoon_utils.py
 | 
| @@ -0,0 +1,62 @@
 | 
| +# Copyright 2017 The Chromium Authors. All rights reserved.
 | 
| +# Use of this source code is governed by a BSD-style license that can be
 | 
| +# found in the LICENSE file.
 | 
| +import collections
 | 
| +import re
 | 
| +
 | 
| +# Named tuple for all monsoon samples.
 | 
| +MonsoonSample = collections.namedtuple('MonsoonSample', 'Timestamp Amps')
 | 
| +
 | 
| +# Regular expression to extract timestamp and amperage from Monsoon's log.
 | 
| +SampleRegex = re.compile(r"(\d+)\s+(?<![a-zA-Z:])([-+]?\d*\.?\d+)")
 | 
| +
 | 
| +def ReadSamplesFromFile(file):
 | 
| +  """ Reads raw samples from a file in the form 'Timestamp Amps', returning
 | 
| +  a list of MonsoonSample tuples.
 | 
| +  """
 | 
| +  samples = []
 | 
| +  for line in file:
 | 
| +    value_match = SampleRegex.match(line)
 | 
| +    # Sometimes there can be transient USB communication errors.  They can be
 | 
| +    # safely ignored.
 | 
| +    if value_match is not None:
 | 
| +      # Some versions of monsoon.py supply timestamp in integer.  Some later
 | 
| +      # versions could in theory supply timestamp as a float.  Collapse all
 | 
| +      # and treat timestamps as if they were integer seconds.
 | 
| +      timestamp_second = int(value_match.group(1))
 | 
| +      amps = float(value_match.group(2))
 | 
| +      samples.append(MonsoonSample(Timestamp = timestamp_second, Amps = amps))
 | 
| +  return samples
 | 
| +
 | 
| +def TransformSamplesWithFrequency(samples, frequency):
 | 
| +  """ Transforms a list of MonsoonSample (with integer second accuracy) into a
 | 
| +  list of MonsoonSample with fractional accuracy, assuming a fixed frequency.
 | 
| +  """
 | 
| +  result = []
 | 
| +  second_samples = []
 | 
| +  second = -1
 | 
| +  last_index = len(samples) - 1
 | 
| +  for i,source_sample in enumerate(samples):
 | 
| +    if second == -1:
 | 
| +      second = source_sample.Timestamp
 | 
| +    if (source_sample.Timestamp != second) or (i == last_index):
 | 
| +      # Now and then the data may have more samples than the given frequency
 | 
| +      # (a desktop OS isn't an RTOS after all). Lets allow it and average out
 | 
| +      # the samples.
 | 
| +      if len(second_samples) > frequency:
 | 
| +        second_frequency = len(second_samples)
 | 
| +      else:
 | 
| +        second_frequency = frequency
 | 
| +      period = 1.0 / second_frequency
 | 
| +      # Samples are represented as halfway through the period.
 | 
| +      time_offset = -(period / 2.0)
 | 
| +      if len(result) == 0:
 | 
| +        time_offset += (second_frequency - len(second_samples) - 1) * period
 | 
| +      for second_sample in second_samples:
 | 
| +        result.append(MonsoonSample(Timestamp = second + time_offset, Amps =
 | 
| +          second_sample.Amps))
 | 
| +        time_offset += period
 | 
| +      del second_samples[:]
 | 
| +      second = source_sample.Timestamp
 | 
| +    second_samples.append(source_sample)
 | 
| +  return result
 | 
| 
 |