SlidingAverage.hh 4.8 KB
/*
 * SlidingAverage.hh
 *
 *  Created on: Dec 3, 2012
 *      Author: f.casimir
 */

#ifndef SlidingAverage_HH_
#define SlidingAverage_HH_

#include <iostream>
#include <list>

#include "Parameter.hh"
#include "ParamData.hh"
#include "DataTypeMath.hh"
#include "Operation.hh"

namespace AMDA {
namespace Parameters {

/**
 * @class SlidingAverage
 * @brief It is responsible to shift data of any ParamData type.
 * @details This class implement the interface Operation.
 */
template<class TParamData>
class SlidingAverage : public Operation {

	typedef typename TParamData::ElementType ElemType;

public:
	/**
	 * @brief Constructor.
	 * @details Create the ParamData type of the input ParamData.
	 */
  SlidingAverage(Process& pProcess, TParamData& paramInput, TimeIntervalListSPtr pTimeIntervalList, double window)
	: Operation(pProcess),
	  _paramInput(paramInput),
	  _paramOutput(new TParamData()),
          _timeIntervalList(pTimeIntervalList),
          _currentTimeInterval(_timeIntervalList->begin()),
	  _window(window), _nanVal() {
	  _paramDataOutput=_paramOutput;
  }

	/**
	 * @overload Operation::write(ParamDataIndexInfo &pParamDataIndexInfo)
	 */
	void write(ParamDataIndexInfo &pParamDataIndexInfo) {
            if ((pParamDataIndexInfo._nbDataToProcess > 0)) {
                if (pParamDataIndexInfo._startIndex == 0) {
                    //init nan value (to init dimensions)
                    _nanVal = _paramInput.get(pParamDataIndexInfo._startIndex);
                    _nanVal << NotANumber();
                }
            }
            
            for (unsigned int index = pParamDataIndexInfo._startIndex; index < pParamDataIndexInfo._startIndex
                + pParamDataIndexInfo._nbDataToProcess; index++) {
                while (!_memTime.empty() && (_paramInput.getTime(index) > _memTime.front() + _window / 2)) {
                    double crtTime = _memTime.front();
                    if ((crtTime >= (*_currentTimeInterval)._startTime) && (crtTime <= (*_currentTimeInterval)._stopTime)) {
                        _paramOutput->pushTime(crtTime);
                        _paramOutput->getDataList().push_back(computeAverage(crtTime));
                    }
                    _memTime.pop_front();
                }
                //Cleanup unnecessary data
                while (!_memTime.empty() && !_mem.empty() && (_mem.front().first < _memTime.front() - _window / 2)) {
                    _mem.pop_front();
                }
                _memTime.push_back(_paramInput.getTime(index));
                _mem.push_back(std::make_pair(_paramInput.getTime(index), _paramInput.getDataList()[index]));
            }
            
            if (pParamDataIndexInfo._timeIntToProcessChanged || pParamDataIndexInfo._noMoreTimeInt) {
                while (!_memTime.empty()) {
                    double crtTime = _memTime.front();
                    if ((crtTime >= (*_currentTimeInterval)._startTime) && (crtTime <= (*_currentTimeInterval)._stopTime)) {
                        _paramOutput->pushTime(crtTime);
                        _paramOutput->getDataList().push_back(computeAverage(crtTime));
                    }
                    _memTime.pop_front();
                }
            }
           
	}
        
        ElemType computeAverage(double crtTime) {
            ElemType mean = _nanVal;
            std::list<ElemType> averageDataList;
            for (typename std::list<std::pair<double, ElemType>>::iterator it = _mem.begin(); it != _mem.end(); ++it) {
                if (it->first >= crtTime - _window / 2. && it->first <= crtTime + _window / 2.) {
                    averageDataList.push_back(it->second);
                                    }
            }
            if (!averageDataList.empty()) {
                mean =  average(averageDataList, _paramInput.getDim1(), _paramInput.getDim2());
            }
            return mean;
        }

	/**
	 * @overload Operation::reset(double pStartTime, double pTimeInt)
	 * @brief reset static data to process another TimeInterval
	 */
	virtual  void  reset() {
		Operation::reset();
		_memTime.clear();
		_mem.clear();
		if (_currentTimeInterval != _timeIntervalList->end())
			++_currentTimeInterval;
	  }

private:


	/**
	 * @brief It is the channel of data to shift.
	 */
  TParamData &_paramInput;

	/**
	 * @brief It is the channel of the data shifted.
	 */
  TParamData *_paramOutput;

  TimeIntervalListSPtr _timeIntervalList;

  TimeIntervalList::iterator _currentTimeInterval;

  /**
   * @brief window size for sliding average.
   */
  double _window;
  
  ElemType _nanVal;

  /**
   * @brief keep some data in memory.
   */
  std::list<std::pair<double, ElemType>> _mem;


  /**
   * @brief list of times over which sliding average must be computed
   */
  std::list<double> _memTime;

};

} /* namespace Parameters */
} /* namespace AMDA */
#endif /* SlidingAverage_HH_ */