movingavg.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. # -*- coding: utf-8 -*-
  2. #
  3. # AWL simulator - Generic moving average
  4. #
  5. # Copyright 2018 Michael Buesch <m@bues.ch>
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License along
  18. # with this program; if not, write to the Free Software Foundation, Inc.,
  19. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. #
  21. from __future__ import division, absolute_import, print_function, unicode_literals
  22. #from awlsim.common.cython_support cimport * #@cy
  23. from awlsim.common.compat import *
  24. from awlsim.common.datatypehelpers import * #+cimport
  25. from awlsim.common.exceptions import *
  26. #from cpython.mem cimport PyMem_Malloc, PyMem_Free #@cy
  27. #cimport cython #@cy
  28. __all__ = [
  29. "MovingAvg",
  30. ]
  31. class MovingAvg(object): #+cdef
  32. __slots__ = (
  33. "__size",
  34. "__items",
  35. "__nrItems",
  36. "__beginPtr",
  37. "__endPtr",
  38. "__avgSum",
  39. )
  40. def __init__(self, size):
  41. if size <= 0:
  42. raise AwlSimError("MovingAvg: Invalid size")
  43. self.__size = size
  44. self.__items = [0.0] * self.__size #@nocy
  45. #@cy self.__items = <double *>PyMem_Malloc(self.__size * sizeof(double))
  46. #@cy if not self.__items:
  47. #@cy raise AwlSimError("MovingAvg: Out of memory")
  48. self.__nrItems = 0
  49. self.__beginPtr = 0
  50. self.__endPtr = 0
  51. self.__avgSum = 0
  52. #@cy def __dealloc__(self):
  53. #@cy PyMem_Free(self.__items)
  54. #@cy self.__items = NULL
  55. def calculate(self, value): #@nocy
  56. #@cy @cython.cdivision(True)
  57. #@cy cdef double calculate(self, double value):
  58. #@cy cdef uint32_t size
  59. #@cy cdef uint32_t nrItems
  60. #@cy cdef uint32_t endPtr
  61. #@cy cdef uint32_t beginPtr
  62. #@cy cdef double first
  63. #@cy cdef double avgSum
  64. size = self.__size
  65. nrItems = self.__nrItems
  66. if nrItems >= size: #+likely
  67. # Get and remove the first element from the list.
  68. beginPtr = self.__beginPtr
  69. first = self.__items[beginPtr]
  70. beginPtr += 1
  71. if beginPtr >= size:
  72. beginPtr = 0
  73. self.__beginPtr = beginPtr
  74. # Append the new value to the list.
  75. endPtr = self.__endPtr
  76. self.__items[endPtr] = value
  77. endPtr += 1
  78. if endPtr >= size:
  79. endPtr = 0
  80. self.__endPtr = endPtr
  81. avgSum = self.__avgSum
  82. if nrItems >= size: #+likely
  83. # Subtract the removed value from the sum
  84. # and add the new value.
  85. avgSum -= first
  86. avgSum += value
  87. else:
  88. # The list is not fully populated, yet.
  89. avgSum += value
  90. self.__nrItems = nrItems = nrItems + 1
  91. self.__avgSum = avgSum
  92. return avgSum / nrItems